Vivek Jalondhara. All writing

Security

Prompt Injection in Document Imports: Keep Data Out of Control

By Vivek Jalondhara · 5 min read
Published

Treat vendor documents and model responses as untrusted inputs, while keeping permissions, destinations, and acceptance outside the model.

A vendor sheet can contain instructions as well as product data. A model asked to interpret the file may encounter a note telling it to change the destination vendor or mark every row as approved. The security question is what authority the application gives that response.

This is an illustrative threat model for a Sheet Parser-style import. It does not identify a vulnerability in the project. The goal is to limit what untrusted document content can influence while retaining useful extraction of descriptions, quantities, and draft prices.

Locate the trust boundary

The authenticated user selects an allowed vendor and uploads a file. The server creates an import job with the authorized workspace, vendor, and source document. Those values come from validated application context. Text extracted from the file may describe products, but cannot grant access to another workspace or approve the import.

OWASP describes indirect prompt injection as instructions embedded in external content a model processes. A footer, hidden worksheet, or extracted comment can therefore influence an import even when the user did not write a malicious chat prompt. Treat every representation of the uploaded document as untrusted, including OCR and intermediate summaries.

Remove authority the extractor does not need

A price extractor needs the relevant document content and a bounded output schema. It usually does not need a tool that sends emails, retrieves arbitrary URLs, or writes accepted catalog records. Keeping those capabilities outside the extraction step limits the consequences of the model following document instructions.

Similarly, do not place unrelated vendor records or credentials in the extraction context. If product matching needs a catalog subset, supply only the authorized fields necessary for that comparison. A prompt telling the model to keep secrets cannot compensate for giving it secrets that the task never needed.

Use prompts as guidance, then enforce boundaries in code

Clearly separate extraction instructions from document content and state that document instructions are data. This improves the task definition, but delimiters are not an authorization mechanism. Keyword filters also miss paraphrases and can reject legitimate notes. Use such checks as signals to investigate, not proof that a document is safe.

After parsing a bounded response, validate the allowed fields and reconstruct the draft explicitly. Copy vendor and workspace identity from the stored job. Assign the pending-review state in server code. Never spread an entire model-produced object into a database write, because an unexpected control field can otherwise become an application decision.

Validate evidence without confusing it with truth

Suppose a document asks the model to label a product as free. A decimal validator may accept the resulting zero. A source reference might even point to a real row. Structural checks therefore need a separate comparison against the relevant source content, with ambiguous or conflicting values left for review.

Check that referenced sheets and rows belong to the uploaded document and are within its bounds. Preserve the original source excerpt for the reviewer instead of presenting only a model-generated explanation. A model can produce an explanation that repeats the same mistake as its extracted value. An additional model check may help triage, but is not independent authorization.

Protect the paths after extraction

Descriptions remain untrusted when displayed or exported. Render them as text in the review interface; introducing arbitrary HTML rendering creates a separate browser risk. Avoid automatically loading document-provided links during review. Any later feature that follows external links needs its own destination and access policy.

Enforce permissions again when a user accepts a draft. The import job's existence does not establish that the current actor still has access. Keep an audit record of the accepted revision and the actor. These checks protect the catalog boundary even when a malicious instruction survives the prompt and appears in model output.

Test the permitted outcome

Create harmless local fixtures containing contradictory instructions, invented approval flags, and requests to switch vendor identity. Verify server-owned values remain unchanged, no external action occurs, and suspicious candidates remain reviewable drafts. Include ordinary documents with instruction-like product descriptions so rejection rules do not make normal imports unusable.

A passing fixture set does not prove prompt injection is eliminated. Report the specific boundaries tested and retain failures for investigation. The tradeoff is a less autonomous extraction step and potentially more review, in exchange for keeping consequential operations under application rules that do not depend on the model's obedience.

Reconstruct a draft using server-owned context

The fields argument has already passed bounded runtime validation. The job comes from a server-side lookup scoped to the authorized user. Explicit mapping means extra vendorId or reviewState fields in model output cannot choose the destination or approve this draft.

Illustrative example · JavaScript · Simplified for explanation

function buildDraft(fields, job) {
  return {
    importId: job.id,
    workspaceId: job.workspaceId,
    vendorId: job.vendorId,
    sku: fields.sku,
    description: fields.description,
    unitPrice: fields.unitPrice,
    currency: fields.currency,
    reviewState: "pending",
  };
}
How the example fits together
  1. Authorize and store import context
  2. Extract untrusted document content
  3. Validate and construct a pending draft
  4. Review and authorize acceptance

Conceptual flow for the example above.

Tradeoff to keep in mind

Explicit mapping protects these control fields only. It cannot detect an invented price, validate the document parser, or enforce the later acceptance endpoint's permissions; those remain separate responsibilities.

Related project: Sheet Parser →

References & further reading

Related posts