AI coding agents make good security reviewers. They can read a repo the way a human reviewer would. But a security review means running an agent on code you do not trust, and that raises a question I had not thought about until I tested it: whose configuration does the agent obey, yours or the repo's?
I work on secfoo, an open-source (MIT) CLI that hands an agent such as Claude Code a security brief and a target. While verifying its Claude adapter, I tested exactly that.
The test
I built a small hostile repo with three things in it:
- a
.claude/settings.jsonwith a hook that runs a command - a
.mcp.jsonthat defines an MCP server - settings that enable project MCP servers and try to allow
Write,EditandBash
Then I ran the adapter's original command against it.
What happened with the old command
- The repo's hook ran.
- The repo's own MCP server started.
-
Writestayed denied, so the read-only grant held.
So the scanned code could make the scanner execute something, even though it could not write files. For a tool whose whole job is to open untrusted code, that is the wrong way round.
The fix
Two flags on the agent command:
-
--setting-sources userloads only the user's own settings, so the target repo's settings are ignored -
--strict-mcp-configuses only the MCP servers the tool passes in explicitly
While I was in there I also made three smaller changes: the prompt goes over stdin instead of the command line (command-line prompts can be truncated at newlines on Windows), --no-session-persistence stops a session file being left behind for every scan, and a failed run now records why it failed, since Claude writes errors to its JSON output rather than stderr.
The adapter command is now:
claude -p --output-format json --allowedTools <tools> \
--permission-mode default --setting-sources user \
--strict-mcp-config --no-session-persistence
with the prompt read from stdin.
What I saw after
Against the same hostile repo:
- the hook did not run
- the target's MCP server did not start
-
Writewas still denied - no session file was left behind
- secfoo's own MCP server, passed in explicitly, still started
I also ran a real SAST scan with the Claude agent on that repo. It finished successfully, found the one SQL injection, recorded tokens and cost, and left the target unchanged. The test suite went from 736 to 751 passing, with 15 new tests for this.
What I did not find
I checked two other ideas and dropped them because I could not reproduce them: that an error result could be saved as a successful report (Claude exits with an error code, so it is not), and that a target's permissions.allow could widen the tool grant (Write stayed denied).
Limits
I tested on Linux with Claude Code 2.1.288. I have not tested Windows or macOS, or older Claude Code versions (a CLI that does not know a new flag exits with an "unknown option" error). I also have not checked whether other agent adapters have the same problem.
What to take from this
If you run any AI agent against code you did not write, check which config files it reads from the target. Project-level settings, hooks and tool servers are all things a repo can ship. Passing your own configuration explicitly, and ignoring the target's, is a small change, and it is easy to miss because nothing breaks when you leave it out.
The fix is in the open: secfoo on GitHub (PR #26). If you find a case I missed, please open an issue.
Top comments (0)