Dependency and software supply chain security¶
Third-party components and build tools become part of the application's trust boundary. Risks include known vulnerable versions, abandoned components, untrusted package sources, malicious install scripts, and compromised build identities. Their consequences depend on where the component runs and what privileges or data it can reach.
Software composition analysis (SCA) identifies dependencies and matches them to advisory information. This differs from source-code analysis, which examines implementation weaknesses. An SBOM is an inventory, not proof that a release is secure. CWE-1395 describes dependence on a vulnerable third-party component and the importance of deployment context.
Risky example: a mutable, unaudited CI install¶
This npm workflow allows manifest/lockfile reconciliation during the build, runs package lifecycle scripts by default, and continues without an advisory check. Whether a particular dependency is vulnerable requires evidence; npm install alone is not a vulnerability.
npm install
npm run build
Safer example: an explicit reproducible-install policy¶
For an npm project whose dependency install scripts are not required, commit and review package-lock.json and use:
npm ci --ignore-scripts
npm audit --audit-level=high
npm run build
Configure CI to stop on a failed command. npm ci installs from the lockfile and fails when it disagrees with the manifest. --ignore-scripts suppresses dependency install lifecycle scripts; it does not make the explicitly invoked build command safe. Review your own build scripts and dependencies that execute during the build.
Some packages legitimately need installation scripts. Test the restriction before adopting it, and use a reviewed, narrowly controlled build process for exceptions. Run builds in isolated workers without production secrets or broad deployment credentials. A lockfile pins a dependency graph; it cannot make a malicious or vulnerable pinned version safe.
npm audit queries the configured registry's advisory service and reports known issues. Its result depends on that data and the dependency inventory. Understand what package information the registry receives, and treat service errors as an unavailable check rather than “no vulnerabilities.” The shown severity threshold is an example policy, not a universal risk decision.
Remediation workflow¶
- Identify the affected direct or transitive dependency and the advisory's affected/fixed versions. Record the data source and scan time.
- Check runtime versus build use, reachable features, privileges, and compensating controls. Absence of demonstrated reachability is not proof of impossibility.
- Upgrade through a reviewed change, refresh the lockfile, inspect unexpected package/source changes, and test the application. Avoid blindly forcing breaking upgrades.
- Rebuild from trusted inputs, verify the released artifact contains the intended versions, and retain its inventory and provenance where available.
Offline advisory data is a dated snapshot. Record its publication/update date and an approved refresh process; an offline scan cannot know advisories published after that snapshot. Review unsupported components even when no current CVE is listed.
Regression test¶
In a disposable local fixture, change the package manifest without updating its lockfile and assert npm ci fails. Verify a benign test package's install hook does not run when scripts are disabled. Exercise the updated application's affected behavior, and ensure CI distinguishes an advisory-service failure from a clean report. These checks do not establish that every dependency is trustworthy.
Related: hardcoded secrets, infrastructure as code, and prototype pollution.
References: CWE-1104 — use of unmaintained third-party components and CWE-829 — inclusion of functionality from an untrusted control sphere.