Office Hours — How do you prevent AI agents from accidentally introducing vulnerable dependencies or malicious code when they autonomously modify your codebase?
A daily developer question about AI/LLMs, answered with a direct, opinionated take.
How do you prevent AI agents from accidentally introducing vulnerable dependencies or malicious code when they autonomously modify your codebase?
You can’t completely prevent it, but you can make it harder and catch it faster. The real answer is layering defenses rather than betting on the agent’s judgment.
Start with sandboxing. Agents like Claude Code and Devin run in isolated environments by default, so they can’t directly push malicious commits to your main branch. Require them to open PRs, not commit directly. That’s your first gate.
Second, automate what you’d manually review anyway. SAST tools (like Snyk, Semgrep) should run on every PR the agent generates, same as any human developer. Dependency scanning is table stakes now. If an agent tries to add npm install sketchy-package, your CI should flag it before it merges.
Practical Example: Locking Down Agent Permissions
Here’s a concrete setup. Your CI/CD should have a separate token for agents with constrained scope:
# .github/workflows/agent-pr.yml
jobs:
agent-changes:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
# DO NOT grant: push to main, tag creation, secrets access
steps:
- name: Run dependency scan
run: |
npm audit --audit-level=moderate
snyk test --severity-threshold=high
- name: Lint and test
run: npm run lint && npm run test
- name: Open PR (no direct commit)
run: gh pr create --base main --title "Agent: $(date)"
The agent gets write access to feature branches only. A human or secondary approval workflow merges to main. Cost-wise, this adds maybe one extra CI run per agent task, roughly $0.02-0.05 per invocation depending on your infra.
Third, scope the agent’s permissions tightly at the code level. Don’t give it write access to your entire repo. Constrain it to specific directories or file patterns. If an agent is only supposed to update tests or docs, lock that down in your CI/CD permissions model.
Fourth, require human sign-off on any dependency changes or modifications to security-sensitive code paths. The agent can propose, but a human approves. This is where you accept the slowdown for safety. For routine refactors or test fixes, you might skip review. For dependencies or auth code, you don’t.
The Harder Problem: Logic Drift
The trickier threat isn’t outright malicious injection. It’s subtle logic bugs or performance regressions that pass tests but break in production. Agents using frontier models like Claude Opus 4.7 or GPT-5.4 have better context windows than a year ago, but they still hallucinate about your codebase internals. Long-context models help, but drift under complex branching logic is real.
Your integration tests and staging deployment are your actual safety net here. If an agent rewrites a critical path and the logic is correct but 40% slower at scale, only load testing catches it. Agents don’t have intuition for performance tradeoffs.
One more thing: agents suggest dependencies they think will help but shouldn’t. Claude Opus 4.7 might recommend adding a heavyweight ML library for a simple classification task. Review agent-suggested deps with the same skepticism you’d use for a junior engineer’s first PR. Check the dependency tree bloat, maintenance status, and CVE history. Agents optimize for “will this work” rather than “is this the smallest thing that works.”
Bottom line: Treat agent-modified code like you treat junior engineer code. Automate the easy checks (linting, scanning, tests), require review for risky changes, and keep humans in the approval loop for anything touching dependencies or security paths. The agents themselves are good enough; the process around them matters more.
Question via Hacker News