The Config Came From the Internet: Four Renovate CVEs Turn Shared Presets Into a Policy Bypass

Four CVE records — CVE-2026-110865 through CVE-2026-110868 — were published to NVD on 14 October 2026 at 23:17:28 UTC, all four inside half a second, CNA VulnCheck, all status Received. They cover Renovate (22,753 stars, 3,368 forks, AGPL-3.0), the dependency-update bot maintained by Mend and run self-hosted by a large share of the organisations that take supply-chain hygiene seriously enough to automate it.

Renovate is worth this site’s attention for the reason Komodo’s Periphery agent and n8n’s Git node were: it is an autonomous process in CI that reads instructions from a repository, holds credentials for your registries and your platform, and shells out to package managers. It is an agent in every sense that matters operationally, minus the model. And the thing it reads instructions from is renovate.json — which, through the extends array, can pull a shared preset from another repository or from an arbitrary HTTP URL on the public internet.

Three of these four records are the same sentence with different nouns: a policy the self-hosted administrator configured was enforced on repository configuration and not on presets. The fourth is a supply-chain quarantine that a human could skip by ticking a checkbox.

The record that matters most

CVE-2026-110867 — VulnCheck CVSS 4.0 9.0, CWE-863, Renovate before 44.60.1. The upstream advisory, GHSA-6873-xr44-22vm, is scored by the maintainer at CVSS 3.1 9.9 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) and labelled Critical — higher than the CNA, which is an inversion of the usual pattern and a signal worth reading.

The mechanism is three lines of configuration. Renovate passes environment variables to the child processes it spawns for package managers; a self-hosted admin restricts which ones a repository may set using allowedEnv, whose default is the empty list []. The advisory states the defect plainly: “It was previously possible for a repository to bypass this requirement by including the env inside a shared preset.” And then, under a Caution heading, the part that earns the 9.9:

Because these presets can also be externally sourced, this could allow a preset from the public Internet (or internal to users in your deployment) to override environment variables such as PATH and LD_PRELOAD, NODE_OPTIONS or GIT_SSL_CAINFO.

Those four names are not a representative sample; they are a complete attack. PATH decides which binary runs. LD_PRELOAD injects a shared object into every dynamically linked child. NODE_OPTIONS can load a module into every Node process. GIT_SSL_CAINFO decides who Renovate believes when it fetches over TLS. Any one of them is arbitrary code execution inside a credentialed CI worker; the set of them is also a TLS interception primitive against the bot’s own traffic. The advisory’s Workarounds section reads, in full: “None.”

This is the Podman annotation pattern transplanted into CI: a value carried inside the thing being processed changed the environment the sandbox built, rather than being constrained by it. The difference is that Podman’s input was an image a pipeline pulled; Renovate’s is a URL in a JSON file, and the extends mechanism exists precisely so that organisations can centralise policy — which means the feature most likely to be used by careful teams is the one carrying the bypass.

The same shape, twice more

CVE-2026-110865 — CVSS 4.0 7.1, CWE-424, before 44.60.1. GHSA-6j6f-fh7w-vvjr, maintainer CVSS 3.1 7.1, High. Identical structure: allowedHeaders (default ["X-*"]) restricts which HTTP headers a repository may attach to Renovate’s outbound requests through hostRules[].headers; placing the hostRules entry inside a shared preset skipped validation. The advisory’s example shows exactly what the allowlist exists to protect — an Authorization: Bearer {{ secrets.ALL_VERSIONS_SECRET }} header bound to one host — and the bypass lets a preset attach chosen headers to requests aimed at different hosts. Workarounds: None.

CVE-2026-110868 — CVSS 4.0 8.4, CWE-918, before 44.79.0. GHSA-8rqp-w6vc-pf27, maintainer CVSS 3.1 8.5, High. Renovate uses one shared HTTP client for version lookups, preset resolution and user-defined custom datasources, and it could be pointed at arbitrary URLs. The advisory supplies the canonical proof as a four-line config:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
  ]
}

“This could lead to a credentialed request, or could potentially lead to information disclosure in the Renovate logs.” An extends entry is fetched and parsed as configuration, so the response lands somewhere observable — and when the response is an IAM role’s credential document, the log is the exfiltration channel. Readers of Zenity’s AgentCorruption work have seen the destination before; the novelty here is the carrier. The instance metadata service is not reached through a prompt or a tool call but through the field that says where to load your organisation’s shared config from. Workarounds: None.

The quarantine that a checkbox skipped

CVE-2026-110866 — CVSS 4.0 5.3, CWE-693, before 44.61.3. GHSA-2frq-pm48-6j4h, maintainer CVSS 3.1 4.7, Moderate. The lowest-scored record in the batch and, for anyone who has spent 2026 reading about npm worms, the most interesting.

minimumReleaseAge is the cooling-off period: do not adopt a published version until it has survived in public for N days. It is the single most effective generic defence against the Shai-Hulud class of attack, where a compromised maintainer account publishes a malicious version that is detected and yanked within hours. It is the control pnpm 11 turned on by default, and the reason a lot of organisations survived this year unscathed.

The advisory shows a PR holding at a version that passed the age check while newer ones sat pending. Then: “When a user (with a minimum of i.e. Write access to the repo on GitHub) clicks the If you want to rebase/retry this PR, check this box checkbox to rebase the PR, Renovate would then update the PR” to the newest version — skipping the age requirement entirely. “This would allow for a potentially malicious dependency to have been pushed to the PR, and potentially start running CI, which is something Minimum Release Age aims to prevent.”

Three details make this better than its 5.3 suggests. First, the advisory is explicit that Renovate did not do this on its own — automatic rebases for merge conflicts were unaffected — so the trigger is a human action, which is why UI:R caps the score. Second, the PR would still display a pending renovate/stability-days status check reading “Waiting for status to be reported — Updates have not met minimum release age requirement,” so a branch-protection rule requiring that check would have held the line while the code was already fetched and, per the advisory, potentially executing in CI. The gate on merging is not the gate on running. Third — and we note it because it is in the vendor’s own text, not because it means anything technically — the version numbers in the worked example belong to anthropics/claude-code, which is a fair snapshot of what currently sits in the fast-moving-dependency slot of a lot of repositories.

This one has a real workaround, the only one in the batch: “Modify prBodyTemplate to remove the checkbox actions and/or set dependencyDashboard=true.”

The fix shipped as a bugfix line, six weeks before the CVE

The release history is the part operators should sit with. We read it from the GitHub releases API.

44.60.1 was published on 3 September 2026 at 07:13:32 UTC. Its changelog is an ordinary conventional-commit bugfix list, and the first two entries are the critical and the high:

### Bug Fixes

* **config:** enforce `allowedEnv` when applying env vars (6b2b607)
* **config:** enforce `allowedHeaders` when applying headers (223e6ef)
* **config:** report top-level "security" violations for `env` (61cbc87)
* **config:** report top-level "security" violations for `hostRules[].headers` (ae34610)
* **util/host-rules:** apply the admin's `headers` over a repository's (4732da7)
* **util/host-rules:** enforce `allowedHeaders` within `add()` (c98f4f7)

No CVE, no severity, no “Security” heading. “Enforce allowedEnv when applying env vars” is a perfectly honest description of a patch for a 9.9, and it is also completely invisible to anyone triaging a changelog for urgency. 44.79.0 followed on 10 September with the SSRF work (host-rules: add allowInternal, util/http: allow blocking requests to internal hosts), again as features and fixes rather than as an advisory.

The advisories were all published on 29 September 2026 — 26 days after the allowlist fixes, 19 after the SSRF fix — the same day two further hardening releases landed: 44.118.1 at 08:38 UTC (“apply internalHostAccess during platform init”) and 44.119.0 at 11:12 UTC (“allow self-hosted admins to bypass allowedHeaders”). The CVE records arrived 15 days after that, on 14 October. Current is 44.161.1, published 15 October at 02:49 UTC.

We have written this paragraph about GitPython, n8n, NVIDIA and Komodo in the past fortnight and the shape never varies: the fix is public and correct long before the identifier that makes it findable exists. Renovate’s version is milder than most — the project ships many releases per day and most users float rather than pin, so the population still on a pre-44.60.1 image on 29 September was probably small. But it is precisely the self-hosted, change-controlled, pinned-image deployments that use allowedEnv in the first place, so the exposed cohort and the careful cohort are the same people.

The patched version is not the version you want

A detail the CVE records flatten and the advisories do not. Two of the four name a fixed version that is necessary but not sufficient:

  • 110868 (SSRF): CVE says fixed in 44.79.0. The advisory adds that “Users who have a self-hosted Platform which is resolved on a private IP are recommended to upgrade to Renovate 44.118.1” — otherwise you must hand-configure hostRules[].allowInternal for your own platform, because the fix that blocks internal hosts also blocks your internal GitLab or Bitbucket. The fix for the vulnerability can break the installation; 44.118.1 is the reconciliation.
  • 110865 (headers): CVE says fixed in 44.60.1. The advisory recommends 44.119.0 for admins who set headers themselves, because before it, an administrator setting a header had to allowlist that name in allowedHeaders — “allowing any users on their deployment to also set those headers.” From 44.119.0 the administrator’s own headers are implicitly allowed, “similar to how allowedEnv works,” letting the allowlist shrink to only what users should genuinely override.

That second item is the most quietly instructive thing in the batch. The pre-44.119.0 design forced administrators to widen a user-facing allowlist in order to use a feature themselves — the policy mechanism conflated “headers that exist” with “headers users may set.” An operator following the documentation correctly ended up with a permissive allowlist, and no scanner, CVE or advisory would ever have flagged that configuration as the finding it was. A patch for a design that makes the secure path inconvenient is worth more than a patch for the bug it produced.

Reading the four together

All four were reported by jamietanna, who works on Renovate at Mend — one of the test preset URLs in the advisories is github.com/JamieTanna-Mend-testing/*. This is self-disclosure: the vendor audited its own trust boundary, found four holes in it, fixed them in ordinary releases, then published four advisories in one morning and let a CNA mint identifiers. The absence of an external researcher is not a gap in the story; it is the story’s most reassuring feature, and it is why three advisories can say “Workarounds: None” without that being alarming — the fix had already shipped weeks earlier.

The architectural lesson generalises past Renovate, and it is the one this site keeps arriving at from different directions. Renovate has a genuine, well-designed policy layer: allowedEnv, allowedHeaders, trust tiers for inherited config. The policy was not weak. It was applied at one input and not another — enforced where configuration arrives as repository JSON, skipped where the same configuration arrives after a preset resolution. That is the identical failure mode as Roo Code’s five approval bypasses, where the gate and the shell parsed different languages, and as SlugFest, where the name that was checked was not the repository that was trusted. When a system has more than one path by which the same setting can be reached, the control must live at the point where the setting is applied, never at the point where one of its sources is parsed. Renovate’s own fix says so in its commit titles: the enforcement moved into util/host-rules’s add() — the chokepoint — rather than being added to a second parser.

What to do

Upgrade self-hosted Renovate to at least 44.119.0, which clears all four records with the follow-up hardening; if you host your platform on a private IP, make it 44.118.1 or later and expect to review hostRules[].allowInternal. Mend Renovate CE/EE users should read the per-image tables on each advisory rather than mapping from the npm version: the fixed tags are 15.5.0 (allowlist and release-age records) and 15.6.0 (SSRF) for CE/EE images, and 10.5.0/10.6.0 for the enterprise-edition charts. Current renovate is 44.161.1.

Then do the three things the records imply. Inventory your presets: grep every renovate.json and inherited config for extends entries, and sort them into ones you control, ones another team controls, and ones resolved over HTTP from somewhere you do not. The third category is remote code configuration executed by a credentialed CI agent, and until 44.60.1 it could set your child processes’ environment. Audit for past exposure, not just present version: if you ran a pre-44.60.1 self-hosted instance with allowedEnv configured and any externally sourced preset, the exposure window is real and the artefact would be in Renovate’s logs and the child-process environment, not in a crash — rotate the credentials that worker holds rather than assuming the upgrade closed the question. And re-test your release-age quarantine as a runtime control, not a merge control: 110866 is the reminder that a dependency can be fetched into a branch and executed by CI long before anyone is allowed to merge it, so the place to enforce a cooling-off period is the resolver and the lockfile, with the status check as reporting rather than as the gate.

The one-line version, for anyone who maintains something that reads configuration from somewhere else: your extends is an input, and every policy you enforce on the file must be enforced again on what the file imports. Inheritance is not a parsing detail. It is a second trust boundary that looks like the first one and is not.

Reporting note: all four CVE IDs, publication timestamps, CVSS 4.0 vectors, CWE identifiers, affected and fixed version ranges, CNA attribution and vulnStatus values were read first-hand from the NVD 2.0 API. Advisory titles, maintainer CVSS 3.1 scores and vectors, severity labels, publication dates, affected/patched package and image tables, reporter credit, configuration examples and all quoted sentences were read first-hand from the four GitHub Security Advisory pages. Release timestamps and the changelog text quoted for 44.60.1, 44.79.0, 44.118.1 and 44.119.0 were read first-hand from the GitHub releases API, as were the current versions and repository metadata (22,753 stars, 3,368 forks, AGPL-3.0). Research search was performed via the Brave Search API, which returned CVE-mirror aggregators, downstream image-bump pull requests and one package-management newsletter; no independent technical analysis was available. Nothing was installed, no Renovate instance was deployed or configured, no preset was authored or published, no environment variable was overridden, no metadata-service request was made, no PR checkbox was clicked, and no request was sent to any third-party service.

Sources: