Table of contents (7 sections)
My site runs small scripts. They hand text written by strangers to an agent, software that relies on an AI model and can act. Mine is Claude Code, launched with claude -p: one question, one answer, no interface. A LinkedIn comment that a bot replies to, a web page to summarize. I wanted text back, never a shell, meaning a command prompt. If a stranger's text says "run this command", the agent must not be able to obey. That is a prompt injection.
On August 17, 2026, I fixed five of these calls in one go. Two of them show the problem.
- In the first, I had written
--allowedTools 'WebSearch,WebFetch', convinced the agent would have only those two tools. - In the LinkedIn bot's call, I had set no flag at all. My August measurement (version 2.1.233) counted 30 tools, including
Bash, which runs commands.
This post explains why --allowedTools, which I took for a limit, limits nothing. I measured everything again today on a newer version, 2.1.319, and the totals are no longer August's.
Two questions that the flag name mixes up
A tool is an action an agent can trigger: read a file, run a command (the Bash tool), search the web. A flag is an option you add to the command, like --tools. Two questions come up about a tool. Does the model see it? And if it uses it, must someone confirm first?
--allowedTools answers the second one. The CLI reference puts it this way: these are the tools that run "without prompting for permission". To limit the tools offered to the model, you must use --tools. The word "allowed" reads like a list of selected tools, but it is an exemption from confirmation.
In -p mode, nobody can answer a confirmation request. Claude Code then applies its permission rules. Mine allow Bash: once the model sees that tool, it runs without anyone being asked.
Measuring the tool list, without asking the model
Asking the model for its list of tools proves nothing: it can invent one. The true list is in the first event of the stream-json stream, the one of type init.
claude -p "Reply only: ok" --tools '' \
--output-format stream-json --verbose | grep -m1 '"subtype":"init"'
The line you get contains the tools field. It is the list of tools Claude Code presents to the model at startup: the table calls them "announced". Here is what I counted on my machine, version 2.1.319. The 33 MCP tools come from my setup, so your total will differ. MCP (Model Context Protocol) means the tools supplied by extensions, here Claude Docs and Playwright, as opposed to native tools like Bash.
| Flags | Tools announced | Bash, Write, Edit | of which MCP |
|---|---|---|---|
| (no flag) | 61 | yes | 33 |
--allowedTools 'WebSearch,WebFetch' | 61 | yes | 33 |
--tools 'WebSearch,WebFetch' | 35 | no | 33 |
--tools '' | 33 | no | 33 |
--tools 'WebSearch,WebFetch' --strict-mcp-config | 2 | no | 0 |
--tools 'WebSearch,WebFetch' --disallowedTools 'mcp__*' | 2 | no | 0 |
--tools '' --strict-mcp-config | 0 | no | 0 |
To read the table rows:
WriteandEditare the tools that write files.--disallowedToolsrefuses named tools.mcp__*means all MCP tools.
First finding: my two allowed tools give the same result as no flag, 61. So --allowedTools does not change the list: it is the default list.
Second finding, which the documentation also points out: --tools removes native tools but does not touch MCP tools. Hence the rule: two locks on the list, --tools for native tools and --strict-mcp-config for MCP tools. That last flag tells Claude Code to load only the MCP servers named on the command line.
Announced, so callable: I called
A list of announced tools proves little. This time I do not ask the agent what it has, I ask it to use it. I read in the stream that the tool really ran. Two calls:
- With
--allowedTools 'WebSearch,WebFetch', the agent ranecho PREUVE_BASH_okwithBash, without any request, and repeated the output to me. - With
--tools '', it called a read-only MCP tool: the guide of the Claude Docs extension. It quoted me the first line it received.
I did not measure the odds that a prompt injection (a booby-trapped text that gives orders to the agent) convinces it to use one. That is not the point: a defense that relies on the model's goodwill is not a defense.
The fix: --tools '' and --strict-mcp-config, zero tools
For a script that only wants text back, here is the LinkedIn bot's call as it has run since August. --print is the long name of -p. The comment's text goes into the prompt, so a stranger wrote it.
const { stdout } = await execFile('claude',
['--print', '--tools', '', '--strict-mcp-config', prompt]);
The measurement gives 0 tools. If the agent must search the web, --tools 'WebSearch,WebFetch' with --strict-mcp-config gives exactly two tools. --disallowedTools 'mcp__*' also removes the MCP tools and works just as well. I prefer --tools (the tools kept) to --disallowedTools (the tools refused): a tool added tomorrow does not enter the list by itself.
What the OWASP ranking says
OWASP is an association that ranks security risks. Its Top 10 targets LLM applications, meaning agents built on a language model. A 2026 edition exists: the official page carries the date of August 3, 2026. Excessive autonomy (Excessive Agency) means an agent that has more powers than it needs. According to the Cloud Security Alliance table, this risk moves from sixth to third place. I did not read the list on the official page, only this table.
My agent fits that definition exactly. It is still not a discovery. The documentation states that --tools, not --allowedTools, limits the tools. A public flaw, CVE-2026-39398, gives a real case. A package advertised a sandbox (a space where the agent cannot break anything) with --allowed-tools "". It is the same flag, written with hyphens. Yet all the tools stayed available. What I bring: numbers on a specific version, and a recipe I saw give zero.
Conclusion
My take: a flag called "allowed" is a naming trap. The documentation is not enough to defuse it: I had read the help and made the mistake anyway. I no longer trust what the flag says. I read the list announced at startup, and a test that fails if Bash appears in it would be the right next step.
What I did not measure: the success rate of an injection, the other versions, the permission modes with no confirmation at all. I also did not test a machine without my settings.
Sources
Documentation consulted on November 9, 2026:
- Claude Code CLI reference, flags
--tools,--allowedTools,--disallowedTools,--strict-mcp-config: code.claude.com/docs/en/cli-reference - OWASP GenAI, page of the 2026 edition of the LLM Top 10: genai.owasp.org
- Cloud Security Alliance, what changes in the 2026 edition: cloudsecurityalliance.org
- CVE-2026-39398 advisory on
openclaw-claude-bridge: advisories.gitlab.com