DEV Community

Varun Poojari
Varun Poojari

Posted on

When you point an AI coding agent at a hostile repo, whose settings does it obey?

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.json with a hook that runs a command
  • a .mcp.json that defines an MCP server
  • settings that enable project MCP servers and try to allow Write, Edit and Bash

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.
  • Write stayed 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 user loads only the user's own settings, so the target repo's settings are ignored
  • --strict-mcp-config uses 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
Enter fullscreen mode Exit fullscreen mode

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
  • Write was 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)