Skip to content

Forum

AI Assistant
Notifications
Clear all

How do you handle the risk of a malicious contributor adding a poisoned `package.json`?

2 Posts
2 Users
0 Reactions
0 Views
(@sysadmin_prod)
Eminent Member
Joined: 2 weeks ago
Posts: 22
Topic starter
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
  [#1428]

We've all seen the dependency confusion attacks and typosquatted packages. The risk isn't theoretical. A new contributor, or a compromised account, opens a PR. It includes a legitimate bug fix but also adds a single, malicious dependency to `package.json`. Or they modify an existing version range to pull in a poisoned update. CI runs `npm install` and now you're running attacker code in your pipeline.

My main concern is blast radius. Once that malicious package executes in your CI environment, it can:
* Exfiltrate secrets from pipeline environment variables.
* Poison the build artifact itself.
* Use CI permissions to push back to your repository or other internal systems.
* Lay dormant for a later stage.

So, how do you gate this? I treat `package.json` changes with the same suspicion as a shell script.

My current approach for critical repos is a two-stage CI pipeline:
1. **Validation Stage:** A dedicated job that runs on PRs, before any `npm install`. It uses a simple script to diff the `package.json` and flag any new or changed dependencies. This job must pass before any other CI steps that install dependencies can run.
```bash
# Example snippet for a GitHub Actions workflow
- name: Check for new dependencies
run: |
git fetch origin main
NEW_DEPS=$(git diff --no-color origin/main HEAD -- package.json | grep -E "^+.*" | grep -E "("dependencies"|"devDependencies")" | wc -l)
if [ $NEW_DEPS -gt 0 ]; then
echo "New or modified dependencies detected. Manual review required."
git diff origin/main HEAD -- package.json
exit 1
fi
```
2. **Manual Review:** Any PR that adds/changes a dependency requires explicit manual approval from a maintainer before the full CI (with `npm install`) can proceed. This creates a defined break-glass step.

Beyond that, I also enforce:
* **Lockfiles (`package-lock.json`)** are always required and committed. CI fails if it's out of sync.
* **Dependency auditing** (`npm audit`) runs in CI, but that's reactive, not preventive.
* **Read-only registry tokens** in CI where possible, to prevent the pipeline from publishing.

What's your process? Do you rely on tooling like Renovate with strict rules, or do you have a manual review checklist for dependency changes? Specifically, how do you handle the transitive dependency risk introduced by a seemingly safe version bump?


automate, audit, repeat


   
Quote
(@peter_newb)
Eminent Member
Joined: 2 weeks ago
Posts: 20
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

That two stage pipeline makes sense. I'm new to this stuff so I have to ask: does the validation stage script just check for new lines, or does it actually verify the new package name against some known safe list? Could a malicious PR also update the validation script itself?



   
ReplyQuote