Auto-Approved Package Install Executes Postinstall Payload
Roo Code, an AI coding agent, can auto-approve package installs without human review. Attackers exploit this by pointing it at a malicious repository whose package.json contains a postinstall script that runs automatically during npm install, giving the attacker code execution on the developer's machine.
How the attack works
An attacker supplies a repository or package containing a package.json with a postinstall lifecycle script. The Roo Code agent, running with auto-approve enabled, executes the package-manager install command without a human confirming it. npm then runs the postinstall script as part of the install process. That script performs a malicious action such as downloading and piping code into a shell, decoding and executing a base64 payload, opening a reverse shell, installing cron or launchctl persistence, appending to a shell profile, or exfiltrating credentials and environment variables.
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- 7f3c1d92-4a68-4f1e-9b0c-2d5e8a71c604
- Severity
- High
Why it matters
An attacker can gain code execution on a developer's or agent's machine, establish persistence, and steal credentials or environment secrets — all triggered by a single auto-approved install with no human review step.
What you can do
- →Disable or restrict auto-approve for package-manager install commands in AI coding agents, especially for untrusted or newly added repositories.
- →Upgrade Roo Code to 3.26.0 or later, where this auto-approve behavior was fixed.
- →Review postinstall scripts in any package before allowing an agent to install it, particularly ones that pipe downloads into a shell or use inline interpreters with child_process/socket calls.
- →Monitor for postinstall-spawned processes that create persistence (cron, launchctl, shell profile edits) or access credential/environment data, and treat native-module build tools (node-gyp, prebuild-install) as expected exceptions.
Known benign look-alikes
- Native-module build postinstalls (node-gyp, prebuild-install, node-pre-gyp) that shell out to fetch prebuilt binaries. These normally invoke node directly and do not pipe a download into a shell, so they miss the payload anchor; if a vendor genuinely ships a curl-pipe-to-sh postinstall it will be reported (deliberately).
- Browser/binary downloader postinstalls (playwright, puppeteer, cypress, esbuild, sharp) - these use the node https module inside install.js, not an exec of curl/wget piped to a shell, and therefore do not match the required anchor.
- Corporate monorepo bootstrap scripts that legitimately run `chmod +x` on files under /tmp or append to a shell profile during `npm install`.
- A developer manually running `npm install` in the editor's integrated terminal on a repository whose postinstall matches one of the payload patterns. The rule only reports (never blocks) and records the full lineage so the analyst can see whether an agent process or an interactive shell drove the install.
- CI/container image builds that run `npm ci` followed by a bootstrap script using curl | sh, if the agent client is installed on the build host.