hamsa software
← All articles
AI tooling7 min read

What an incoming email can change in an AI task

Follow a recipient change from external text to a proposed tool call, and see where a useful assistant needs a boundary outside its prompt.

A circle approaches a geometric arch on a horizontal path, representing the boundary between external content and an authorised task.

A change of address inside the evidence

Alice asks an assistant to draft an update about order 17 for the customer address on the approved job. An email in the background material asks for a copy at a different archive address. Most of the proposed draft can be entirely appropriate while that one changed tool argument puts the order information in a draft for a recipient outside Alice’s task. The recipient is where I would follow the request, rather than wait for an obviously suspicious sentence in the email.

The new address could be a genuine correction, a mistake, a forwarded instruction or a malicious request. The application does not have to settle the sender’s motive before asking who can change Alice’s job. It needs a supported route for a real contact update, and it needs to keep that route separate from merely reading the proposed address. Otherwise even a politely phrased piece of background material can become authority over the next action.

OWASP describes indirect prompt injection as external content influencing a model’s behaviour, and recommends separating that content and limiting privileges. [1] Labelling the email as external is useful. It does not establish what happens if the model still proposes the changed recipient. That last part belongs to the code which can create a draft, retrieve a document or send a message.

Write the permission before reading the email

The original teaching fixture gives the trusted job five fields: tenant, user, recipient, allowed document identifiers and action. The recipient is customer@example.invalid; the only document is order-17; the permitted action is draft. The addresses use a reserved invalid domain, and the program performs no email or network operations. It models decisions rather than claiming to defeat an actual model attack.

These fields come from the authorised application flow, not from a model’s summary of the email. Otherwise the model could rewrite both the proposal and the supposed evidence that it is permitted. Store the job scope in a form the execution service can retrieve independently. A string saying “the user approved this” in tool arguments is still a string supplied by the caller, even when it sounds convincingly administrative.

The scope should be narrow enough to answer a useful question. “Can access email” is too broad to decide whether this order summary may go to this address. “May draft an update about order-17 for the known contact” lets the server compare the proposal with a specific task. It also preserves a valuable distinction: permission to prepare a draft does not automatically include permission to dispatch it.

Inspect the exact boundary crossing

Suppose the model quotes the email accurately and proposes action draft, document order-17 and recipient archive@example.invalid. The action and document match the job; the recipient does not. Comparing that argument with customer@example.invalid on the trusted job is enough to reject this particular proposal, even if the model has misunderstood which instruction should govern it. A useful draft and an unauthorised destination can occupy the same tool call.

A warning inside the system prompt can still help the model avoid making that proposal. It reduces unhelpful output and saves the person from repeated interruptions. But the enforcement rule does not ask whether the model’s explanation sounds trustworthy. It checks the concrete values which would produce the effect. OWASP’s authorisation guidance calls for least privilege and permission checks on every request. [2] A model-generated request is another request crossing that boundary.

Alice’s recipient can be correct while the draft contains information her task never allowed. The model might have read another attachment earlier or generated an unsupported claim. Limit what enters the task context, preserve source relationships where practical and review the resulting draft for its purpose. Comparing recipients protects the destination choice; checking the sources and body still has a separate job.

Two other fixture cases change draft to send or add staff-9 to the document list; each fails its own check. A well-formed email address would still pass a syntax validator, so syntax is not the question being decided.

The server also needs the tenant and actor from authenticated context. If the caller can freely supply those alongside the address, an internally consistent proposal can still target another tenant’s job. Compare ownership, current permission and the requested effect together.

The approved document list must also govern the actual reads. Validating order-17 and then loading a broader default set of attachments would leave the comparison looking correct while the draft gained information the job never authorised. Keep the checked scope attached to document loading, rather than treating validation as a preliminary formality. The miniature program starts after authentication and models these decisions without creating a draft in an external service; the real action path has to supply those surrounding controls.

Where a quoted address tries to become authority

An original synthetic draft task has an approved recipient and document scope. External email content proposes another address; the server checks the proposal against the trusted job.

Follow the labelled arrows. On a narrow screen, scroll sideways if needed.

Where a quoted address tries to become authorityTrusted job: draft only. Alice authorises an order-17 draft for customer@example.invalid. The permitted document scope is order-17 only. External email: content. The email asks to use archive@example.invalid. It may be summarised but cannot revise the trusted job. Model-proposed draft. The proposed tool arguments include order-17 but target archive@example.invalid. Server checks against immutable job. The recipient differs from the authorised customer@example.invalid recipient. Denied: no draft created. This toy policy rejects the recipient change rather than treating the external request as task authority. From Trusted job: draft only to Server checks against immutable job: Defines authority. From External email: content to Model-proposed draft: Supplies external content. From Model-proposed draft to Server checks against immutable job: Arguments require authorisation. From Server checks against immutable job to Denied: no draft created: Recipient mismatch.Defines authoritySuppliesexternalcontentArguments requireauthorisationRecipientmismatchTrusted job: draft onlyAlice authorises an order-17draft forcustomer@example.invalid. Thepermitted document scope isorder-17 only.External email: contentThe email asks to usearchive@example.invalid. Itmay be summarised but cannotrevise the trusted job.Model-proposed draftThe proposed tool argumentsinclude order-17 but targetarchive@example.invalid.Server checks againstimmutable jobThe recipient differs fromthe authorisedcustomer@example.invalidrecipient.Denied: no draftcreatedThis toy policy rejects therecipient change rather thantreating the external requestas task authority.
Authored defensive trace with reserved invalid-domain addresses. The downloadable fixture checks authorisation decisions; it does not run a model or send email.

What if the customer really has moved?

A genuine address change needs a supported route. The application might open a contact-update case, show the proposed destination and seek the business’s required verification. After verification, a new or revised authorised job can use the new address. This preserves the email as evidence of the requested change while recording separately who established that the destination was acceptable for order information.

That extra step has a cost. If every harmless wording suggestion demands approval, the assistant becomes a particularly chatty form. Separate changes that alter exposure or effects from changes that improve the draft within its scope. Correcting punctuation is different from adding a confidential attachment, switching recipients or changing a draft into a send. Make those distinctions in the product’s task model rather than asking the model to improvise them each time.

A useful screen can show the original and proposed destination beside the reason for the change, while keeping the draft on hold. It also avoids a misleading success message when the assistant has merely recorded a request for someone else to verify. The state of the task should distinguish a proposed contact update from an approved destination and from a completed draft.

A recipient can also be legitimate while the current user has lost permission to access the order. The fifth fixture case withdraws permission after the job exists; the server denies the otherwise unchanged proposal. An old job records what was intended, not an indefinite grant. The real implementation needs a current permission check at the appropriate execution boundary, including tenant and object relationships, rather than assuming the initial screen remains authoritative forever.

A real address change has its own lifecycle

The order-17 draft can remain held while a requested destination change is verified.

Follow the labelled arrows. On a narrow screen, scroll sideways if needed.

A real address change has its own lifecycleEmail proposes archive@example.invalid. Record the proposed contact change as an external request, not as authority to revise the order-17 draft. Verification pending: keep the draft held. The business-required check is incomplete. Retain the original task scope while verification is pending. New destination verified. After the supported contact-update process succeeds, create or revise the authorised job. Check revised job; prepare in-scope draft. The server checks the current actor and exact task values. Sending remains a separate permission. From Email proposes archive@example.invalid to Verification pending: keep the draft held: Verify the proposed contact change. From Verification pending: keep the draft held to New destination verified: Supported verification succeeds. From New destination verified to Check revised job; prepare in-scope draft: Current job permits the recipient.Verify theproposedcontact changeSupportedverificationsucceedsCurrent jobpermits therecipientEmail proposesarchive@example.invalidRecord the proposed contactchange as an externalrequest, not as authority torevise the order-17 draft.Verification pending:keep the draft heldThe business-required checkis incomplete. Retain theoriginal task scope whileverification is pending.New destinationverifiedAfter the supportedcontact-update processsucceeds, create or revisethe authorised job.Check revised job;prepare in-scope draftThe server checks the currentactor and exact task values.Sending remains a separatepermission.
The fixture performs no email or network operation. Draft, destination approval and dispatch are different permissions.

Make the failure useful to the person

A denial should explain the relevant boundary without reproducing secrets: “This draft proposes a recipient outside the approved task.” Preserve the original authorised task and the proposed change for an appropriate review path. Do not quietly substitute the old address and claim the requested change succeeded. The person needs to know whether a draft was created, held or rejected, especially if they are trying to finish a time-sensitive customer reply.

If a task really needs wider scope, show the exact change: a different recipient, another document or permission to send rather than draft. That is something a person can evaluate. A general “allow everything” response to a denial would throw away the distinctions the application has just made. The process can still be quick when the proposed revision is clear; the person should leave it knowing which action is now permitted and which part remains held.

The downloadable policy model allows the authorised draft and denies the changed recipient, send action, extra document and withdrawn permission. Those deterministic checks answer whether a proposed call fits the job. A model trial asks another question: what calls does misleading external text cause it to propose? Inspect both the proposed arguments and the person’s resulting screen. A correct server rejection can still leave an unusable workflow if the assistant keeps presenting the same rejected change as though the draft had succeeded.

The email can still help the assistant write a useful reply. It can also open a legitimate contact-change question, with the proposed address and reason ready for verification. Until that process supplies a revised job, the server has a specific reason to hold this draft. Once it does, the same comparison can permit the new recipient without pretending the original email ever had the authority to change the task by itself.

Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.

See the Payment Operations Pilot

References & further reading

Primary sources behind this article. Living documentation may change.

  1. OWASP LLM01:2025: indirect prompt injection and mitigation boundaries
  2. OWASP: least privilege and permissions on every request
Hamsa Jama

Practical engineering. A human perspective.

More about Hamsa Software and the person behind it. Editorial notes.

A few more things
worth a read.

Back to the reading room
AI tooling7 min read

The prompt did not change. The system did.

Version the resolved configuration around an AI response so comparisons, investigations and rollback refer to the system that actually ran.