EresusSecurity
Back to Research
Guide

CI/CD Build Script Security: postinstall and build.rs Risks

Eresus Security Research TeamSecurity Researcher
August 26, 2026
4 min read
GuideSoftware Supply Chain

In the ArrayRef attack, the payload executed during cargo build. In the axios attack, it executed during npm install. The common thread: in both ecosystems, package managers run code you did not write, under your identity, at install and build stages. This guide maps the build-time execution surface ecosystem by ecosystem and ties it to auditable controls.

Why build scripts are a distinct security problem

Dependency code runs at two different times, and the risks differ:

  • Import/runtime: Runs when your code calls a dependency's function. Static analysis, SCA tools, and code review see this surface.
  • Build/install time: Runs the moment a package is downloaded — before any function is called. It bypasses code review, is not covered by application tests, and typically executes with full user privileges on a developer machine or CI runner.

For attackers, the second surface is more valuable: an execution point inside a secret-rich environment, with network access and weak logging.

The execution surface by ecosystem

npm / Node.js

Mechanism When it runs Notes
preinstall / postinstall / prepare During npm install Lifecycle scripts of transitive dependencies also run
node-gyp rebuild Native module installs The compile toolchain itself is an attack surface
Lifecycle script env vars During install npm_config_* injection is a known vector

Control: setting npm config set ignore-scripts true locally is a reasonable default, but teams doing so must manage an allowlist for packages that genuinely need scripts.

Cargo / Rust

Mechanism When it runs Notes
build.rs cargo build, cargo check, IDE indexing The ArrayRef payload lived here
build-dependencies Compiled before build.rs A build-dependency containing network crates (ureq, reqwest) is a red flag
proc-macros Generate code during compilation A malicious proc-macro can evade static analysis

Control: automatically flag new dependencies containing a build.rs in PR diffs; give special review to network crates appearing under [build-dependencies].

Python / Java / Go

  • Python: arbitrary execution via setup.py/pip install is still possible; prefer wheels and use --require-hashes.
  • Maven/Gradle: plugins execute code within the build lifecycle; pin plugin versions.
  • Go: go generate and cgo compilation; restrict egress beyond the module proxy.

Concrete audit steps

1. Map your current surface

# npm: which lifecycle scripts are defined?
rg -n '"(pre)?(post)?install"|"prepare"' --glob 'package.json' node_modules -g '!**/.bin/**' | head -40

# Cargo: which packages ship build.rs, and what do they build-depend on?
fd -H 'build.rs' ~/.cargo/registry/src | head
rg -n '\[build-dependencies\]' --glob 'Cargo.toml' ~/.cargo/registry/src -l | head

2. Gate new build scripts at the CI door

Turn these diff patterns into automatic warnings on dependency-bot PRs:

  • a new "postinstall" hook or build.rs file,
  • a new networking library under [build-dependencies],
  • network/exec API transitions inside an existing build script (require('http'), Command::new, urllib, fetch).

3. Harden the build environment

  • Build on ephemeral runners; never feed workspace caches from untrusted PRs.
  • Enforce registry/mirror egress allowlists (for example, only registry.npmjs.org and your internal mirror).
  • Separate signing and deployment credentials from build steps; use OIDC-based short-lived tokens.

4. Permanent control after incidents

In incidents like ArrayRef, finding the malicious version in a lockfile is not enough — treat everything that ran in that environment as compromised. Our ArrayRef analysis and axios breakdown cover real-world versions of this chain.

How Eresus approaches this

Eresus Security reviews the build-time execution surface across three layers together: repository, CI configuration, and runner isolation. Our source code analysis work — including dependency security and CI/CD pipeline security reviews — delivers these controls adapted to your pipeline with evidence.

Frequently asked questions

Is ignore-scripts sufficient protection?

No. Native modules and some popular packages cannot install without lifecycle scripts, allowlist maintenance degrades over time, and the policy quietly gets relaxed. ignore-scripts is meaningful only alongside mirrors, quarantine, and diff review.

Doesn't SCA scanning catch build.rs risks?

Most classic SCA tools check known-vulnerability databases; a brand-new malicious package (like ArrayRef) will not be listed yet. Behavior-focused checks are required: new build scripts, unexpected build-dependencies, network access from build stages.

Isn't a private registry enough?

A mirror narrows the attack window but does not stop a compromised legitimate package. Mirrors deliver value when combined with minimum release age policies and automated behavioral scanning.

Security Validation

Have you tested this risk in your own system?

Eresus Security delivers real exploit evidence through penetration testing, AI agent security, and red team operations.

Request a pilot test

Related Research

Related Services