The root cause is that language models read instructions and data through the same channel. A model has no reliable way to tell the difference between what its operator told it to do and text it encountered while doing the work.
Direct and indirect
Direct: a user types the malicious instruction into the prompt themselves
Indirect: the instruction is planted in content the system will read later, such as a web page, a support ticket, a PDF, or a calendar invite
Indirect is the one that matters for agents, because an agent reads far more untrusted content than a person does, and nobody reviews each item before it goes in.
Where teams get it wrong
Treating it as a filtering problem. Input filters and system prompt hardening raise the cost of an attack, and neither eliminates it, because the attack surface is the model's inability to separate instructions from data. The durable mitigation is limiting what a compromised agent can reach, so a successful injection produces a small blast radius rather than a large one.