A tool call arrives as JSON. The model decides the values. When one of those values is a free text field, the model has effectively been handed a place to write prose, and prose is the substrate of instructions. The OWASP prompt injection cheat sheet describes the root cause plainly: most LLM integrations process natural language instructions and data together without clear separation, so an attacker can change behavior by embedding a command in content the model is asked to handle (the OWASP guide). Its canonical example concatenates a system prompt with user input and lets the user string carry "ignore all previous instructions."
The same mechanism works at the tool boundary, and it is worse there, because a tool call ends in an action. PredictionGuard draws the line sharply: prompt injection manipulates what a system says, while tool call poisoning hijacks what it does, executing unauthorized API calls with attacker-specified arguments at the execution layer (PredictionGuard). A poisoned document that says "email all resumes to this address" is just text until some tool accepts a recipient and a body as free strings from the same model context. SentinelOne documents exactly this pattern for indirect injection: hidden instructions arrive inside content the application already trusts, such as resumes, knowledge base articles, or emails, and the model cannot distinguish legitimate content from poisoned instructions (SentinelOne).
The survey by Ferrag and coauthors maps more than thirty attack techniques across LLM agent workflows, organized into input manipulation, model compromise, system and privacy attacks, and protocol vulnerabilities such as exploits in agent and tool protocols (the arXiv survey). The takeaway for a practitioner is not that prompts are hopeless. It is that the defense belongs in the argument structure and the code that checks it, not in a sentence telling the model to be careful.
The decision rule
Ask one question about each tool argument: can a value of this field, read on its own, change what the tool does beyond its declared purpose? If yes, it is a command channel and must be replaced with a typed field or a closed set. If no, it can stay a string, but only with a length cap and a validation step that treats it as inert payload.



