Ledgerline routes an employee’s support request through an assistant API, a model provider, and a refund tool. A Jira ticket contained text requesting a customer refund; the assistant treated that text as an instruction, then the tool executor used a shared payments service account to issue it. The requester lacked refund permission, but the backend never checked the requester at the point of action. No malware or stolen credential was needed. Untrusted ticket text entered the agent loop and reached a privileged operation that the application had already made available.
This failure combines prompt injection, where untrusted text changes an application’s model-directed behavior, with excessive agency, where the application gives that behavior authority beyond the originating employee’s rights. OWASP calls these LLM01 Prompt Injection and LLM06 Excessive Agency in its 2025 guidance, published by the OWASP GenAI Security Project in November 2024. Prompt wording cannot authorize a refund because the model only produces text; the server decides whether a payments action runs.
The refund passed because Ledgerline allowed one request to cross several trust boundaries without preserving who caused it. An employee message is untrusted. A retrieved support document is untrusted, even when Ledgerline stored it. A tool result is untrusted input to the next model call. Model output is also untrusted, because a proposed refund action is not evidence that the employee may perform it.
The assistant API authenticates the employee before assembling the prompt. Retrieval authorization restricts documents to the employee’s tenant and entitlements before document text joins the prompt. The tool executor receives the authenticated principal and the requested parameters, then enforces the action policy before it contacts the payments system. The audit log records the principal, requested action, decision, and result. The model provider generates a candidate action, but never grants permission. The request path makes each boundary visible:
The path separates text processing from authority. Authentication can reject an unknown caller, retrieval can withhold an unauthorized customer record, and the tool gate can refuse a refund even when the model strongly recommends one. An audit record cannot prevent the action, but it lets Ledgerline establish which principal, policy decision, and parameters produced the result.
Because each boundary rejects a different failure, Ledgerline returns a stable status contract rather than treating every denial as a model error. 401 Unauthorized means the request has a missing, invalid, revoked, or compromised credential. 403 Forbidden means an authenticated employee lacks the required scope, such as requesting a refund without refund authority or attempting retrieval outside the employee’s entitlements.
Other stages use narrower outcomes:
409 Conflict means the first request using an idempotency key is still running.422 Unprocessable Content means model output failed Ledgerline’s required action schema, or an idempotency key was reused with different parameters.429 Too Many Requests with Retry-After means a tenant exhausted a rate or spending limit.503 Service Unavailable means Ledgerline cannot enforce a required counter or an open circuit breaker blocks a provider call.504 Gateway Timeout means the model provider exceeded Ledgerline’s deadline.A status code identifies the boundary that made a decision. If a customer lookup is denied before prompt assembly, Ledgerline returns 403 Forbidden; no retrieved document reaches the provider. If a proposed refund has malformed parameters, the server returns 422 Unprocessable Content before the tool executor contacts payments. These outcomes turn refusal into observable backend behavior rather than a sentence in a system prompt.
Authority rule A shared service identity may transport a request, but it must not replace the employee principal used to authorize the action.
The opening incident is a confused deputy. Ledgerline’s refund executor held broad service authority and spent that authority for an employee who did not possess the corresponding permission. The payments API may still validate Ledgerline’s service credential, but it cannot recover the employee’s missing entitlement unless Ledgerline carries and checks that principal. Moving the control earlier to prompt assembly leaves later text, tool results, and model output able to alter the proposed action.
The reliable enforcement boundary is the server-side tool handler, where Ledgerline has both facts needed for a decision: the authenticated employee principal and the concrete refund parameters. Prompt rules can guide model behavior, and the provider can return a candidate tool call, but neither mechanism enforces Ledgerline’s authorization policy. Which stage should first stop the Jira-ticket refund: prompt rules, the model, the tool handler, or the payments API?