An enterprise assistant is only as trustworthy as the text it reads, and people wrote most of that text, not you. Prompt injection in shared documents is what happens when instruction shaped text sits in a wiki page, a ticket comment, or a shared spreadsheet, and an assistant later pulls that text into its context while answering an ordinary question. The corpus was meant to be reference material. The planted lines read like orders. This post covers who can plant them, why access rules do not save you, and what to change.
What makes a shared corpus a delivery channel?
A shared corpus becomes a delivery channel the moment an assistant reads it automatically and nobody reviews what goes in. Take an invented company, Acme Logistics, and its assistant Acme Assist. It is wired into the company wiki, the ticket tracker, the shared drive, and the chat archive. An employee asks what the refund policy is for damaged freight. The retrieval layer finds the five most relevant chunks across all four systems and pastes them into the model’s context above the question.
Nothing in that flow checks whether a chunk describes policy or issues a command. This is the mechanism behind indirect prompt injection, where the hostile text arrives through content the model was asked to read rather than through the input box. What changes at work is who gets to write into the source. A public web page has to be fetched. A wiki page is already inside the trust boundary and pulled in by default.
Why does the attacker not need to be an outsider?
The attacker does not need to be an outsider because most corpora an assistant reads accept writes from people who were never treated as a security relevant party. Look at who can put text into Acme Logistics systems on any Tuesday. A contractor with a wiki account for a three month project. A customer filing a ticket, whose subject line and message body land in the tracker verbatim. A marketing form that opens a ticket automatically. An intern taking meeting notes into the shared drive.
Every one of those is a write path into a corpus the assistant trusts, and none was designed as one. The ticket case is the sharpest: nobody at Acme decided the public could contribute text to the assistant’s knowledge base, yet that is what happens once tickets are indexed. The same holds for any store the model reads back later, which is why poisoning a retrieval corpus and poisoning an agent’s own memory end in the same place: text of unknown origin arriving as trusted background.
Ask who can write into every store your assistant reads. That list is almost always longer than the list of people you would trust to give the assistant orders.
Why do permissions not stop prompt injection in shared documents?
Permissions do not stop this because the assistant reads with its own access, not the access of the person who asked. Acme Assist was given broad read rights so it could answer anything from anyone. When a junior analyst asks about freight refunds, retrieval runs as the service account and reaches files the analyst could never open. Any instruction sitting in those files is read by an identity with more authority than the requester ever had.
That is a confused deputy in the classic sense. A privileged component acts on input from a less privileged source and applies its own rights. The person asking did not intend the action. The person who wrote the text had no rights at all. The assistant supplies the authority for both. If it can also update tickets, post to channels, or send mail, the planted text becomes an action under a trusted identity, logged as the service account doing something normal.
Why is the delay the hardest part to reason about?
The delay is the hardest part because planting and firing are separated in time, so the two never look connected. Someone edits a page in March. In July an employee asks a question whose top retrieval hit is that page, and only then does the model read the lines. There is no session to correlate.
Two things follow. The person who triggers the payload is an employee doing their job, so alerting on the requester finds nothing. And one planted chunk fires again for everyone who asks a related question, until someone opens the source page and reads it. Retrieval logs show the chunk was returned, not that it changed the answer.
Which surfaces actually carry this?
The surfaces that carry it are the ones people forget are text at all. Documents are the obvious case. The short fields are the ones nobody reviews.
- Wiki pages. Editable by most of the company, rarely reviewed after the first version, indexed by default as the official reference.
- Ticket titles and comments. Free text from customers and contractors. Titles are the worst case: short, always indexed, never read closely.
- Shared spreadsheets. Cell contents, hidden columns, and comment threads all become text once the file is parsed.
- Meeting notes. Transcripts and pasted notes, written by whoever was in the room, guests included.
- Chat channels. Archives are conversational, so instruction shaped sentences look natural there.
- File names and paths. A file name is text the model sees, and almost nobody validates it.
How do you defend against this?
You defend by making origin visible to the model and by scoping retrieval to the asking user rather than to the assistant. Both change the structure instead of guessing which sentence is hostile.
- Label every chunk with its origin and author, and keep the label attached. A chunk arriving as bare text has lost the one fact that matters. Carry the source system, the document, the last editor, and whether that editor is internal, and put the label in front of the model with the chunk, not in a header it saw once.
- Retrieve as the asking user. Filter the index by what the requester may already see, not by what the service account may see. This does not stop planted text, but it removes the privilege gap the confused deputy needs.
- Treat all corpus text as data behind a boundary. Retrieved content is quoted material the model summarizes and cites, never a source of goals. Say so in the system prompt, and build the pipeline so an instruction in a chunk has nothing to reach for.
- Require confirmation for any action that came from retrieved content. If a write, a send, or a ticket update traces back to a document rather than to the human’s own words, stop and ask. Show the person the chunk that suggested it.
- Watch for instruction shaped text at ingestion. Flag imperative sentences addressed to an assistant, hidden formatting, and text naming the assistant when a document is indexed. That catches careless cases only, so treat it as a signal, not a gate.
- Review who can write into every indexed corpus. Name the population that can add text to each source, then decide whether public ticket bodies belong in the same index as approved policy pages.
The mistake underneath this is an assumption nobody wrote down: that content living inside the company is content the company vouched for. It is not. It is text a large group of people were allowed to type, read back later by a component with more authority than any of them. That gap between what a system assumes and what it enforces is what an autonomous researcher that tests assumptions is built to find. More on that approach on our about page.
This attack is one entry in our AI Agent Security Field Guide, a map of how AI agents get attacked and how to defend each one.
Frequently asked questions
What is prompt injection in shared documents?
It is an attack where someone writes instruction shaped text into a wiki page, ticket, spreadsheet, or chat archive that an assistant later pulls into its context. The assistant was told to treat that corpus as reference material, so it reads the planted lines as part of a normal request and can act on them.
Does the attacker need access to the company network?
Often not. Support tickets, web form submissions, vendor replies, and contractor wiki edits all place text into systems an assistant reads. Anyone who can add content to an indexed store is a writer into the assistant’s knowledge base, whether or not you meant them to be.
Why do file permissions not prevent it?
Because the assistant usually retrieves with its own broad access rather than the access of the person asking. It reads the planted text with its privileges, not theirs, which is a confused deputy situation. Scoping retrieval to what the asking user may already see removes that gap.
How do you defend against it?
Label every retrieved chunk with its source, author, and whether that author is internal, and keep the label in front of the model. Retrieve as the asking user, treat all corpus text as quoted data rather than goals, require confirmation for any action traced to retrieved content, and review who can write into each indexed store.
Put an autonomous researcher on your own systems
UnboundCompute is an autonomous security researcher that reasons about how an application fits together and proves the access control and injection bugs it finds. We are opening a small number of founding design partner seats: private early access pointed at a staging target you choose, and a say in what it looks for. If your team ships software worth pressure testing, apply to the design partner program.
