
Keep AI-Exported Text from Becoming Spreadsheet Formulas
A valid export can still turn untrusted text into a spreadsheet formula. Choose explicit cell types, a known import path and tests that preserve data without granting it execution.
Read MoreDisplaying a remote image is a network action. Separate text, links and media so an AI answer cannot quietly authorize an outbound request before the reader clicks.

A support worker opens an assistant's answer. Before anyone clicks a link, the browser requests an illustration from an external server. A unique identifier in the image address can associate that request with a particular reference. If private information has been placed in the address itself, requesting the picture sends that information too.
This is a constructed situation, not a reported ZharfAI incident. It exposes a product decision that can disappear behind the instruction to “render Markdown”: which parts of an answer may be displayed as inert content, and which may initiate contact with another recipient? A remote picture is not only decoration. Loading it can be an outbound action.
An answer can contain ordinary text, a navigable link and an embedded image. They need not receive the same authority. Text can be displayed without contacting a new destination. A plain link normally waits for a user action, but automatic previews or prefetching change that behavior. An external image needs a retrieval path unless an existing cache or another mechanism supplies it.
OWASP's prompt-injection prevention guide explicitly identifies rendered HTML and Markdown images as an exfiltration risk and calls out streaming-related rendering problems. That establishes a mechanism worth controlling, not an incident rate for your application. It does not mean every remote image receives an entire conversation: the actual request and the information encoded in it matter.
The relevant question is therefore more precise than “did the model produce a dangerous answer?” Ask who constructs each request, when it starts, what it carries and which recipient receives it. Include services that fetch on behalf of the interface. A background preview worker can cross the same boundary even when the browser itself sends nothing to the external host.
Our recommendation for an assistant handling sensitive enterprise information is to treat generated media references as proposals, not permissions. The application should authorize the effect before turning the reference into something capable of fetching. The model's helpful description of a picture does not establish that authorization.
Preventing script execution remains essential. However, an ordinary HTTPS address can still be inappropriate for a particular conversation. A restriction on dangerous syntax and a decision about the recipient of private information answer different questions.
The react-markdown documentation describes a default URL transformation that permits protocols including HTTPS, along with element filtering and custom components. It also warns that insecure transformations, plugins or components can undermine security. The inference for product teams is straightforward: an accepted protocol is not approval of the destination or the data inside its address.
This resembles the interpreter boundary in our spreadsheet-export guide: content that was data in one stage acquires behavior in another. Here that behavior need not be JavaScript execution. Merely fetching an image can be the unwanted effect. A test reporting “no script executed” therefore does not settle the confidentiality question.
Inventory the components that interpret the answer: the Markdown renderer, link-card builder, image loader and report exporter. Record which one can initiate a request. A check applied to an early string is insufficient if a later component reconstructs or reinterprets the destination differently. Keep the policy intact at the last boundary before contact.
Separate information accompanying a request from information contained in its destination. A referrer policy affects the former. It does not cleanse an address that the application has already constructed from private context.
MDN's Referrer-Policy reference explains that no-referrer omits the Referer header. This is useful protection, but the receiving server still needs the requested image path and query. A private identifier placed there is not removed by suppressing the header. “We send no referrer” is consequently a narrower statement than “we send no sensitive information.”
Review these as two separate questions: what can the recipient learn from the connection and its accompanying information, and what has the application put into the requested address? The second question still applies behind an image proxy. An approved reference should identify an approved asset, not provide the model with a free-form channel for encoding conversation content.
Avoid treating every incident as equivalent. A request revealing that a particular reference was opened, a request carrying a customer identifier and one carrying confidential text have different consequences. Preserve that distinction when investigating. Do not claim a full-content disclosure merely because an external image was present.
For a sensitive assistant, let the model select from asset identifiers already eligible for the task. A server can resolve the identifier after checking the current user, conversation and resource. An unguessable identifier is not itself an access-control decision; the resolver still needs to establish permission to view the asset.
The following is ZharfAI's proposed policy table, not a library default or a universal requirement for every public website.
| Proposed answer element | Recommended behavior | Important condition |
|---|---|---|
| Text, headings and tables | Render without a new external fetch | Restricted formatting and permitted content |
| Image from controlled storage | Resolve an asset identifier and display it | Check this user's access to this asset |
| Public source link | Show a recognizable destination for deliberate navigation | Disable automatic previews or authorize them separately |
| Arbitrary model-supplied image address | Render an inert placeholder or reject it | Do not fetch merely to discover what it contains |
| Necessary external image | Admit it through a dedicated retrieval path | Approve the recipient and outgoing data before fetching |
A public catalog might legitimately import images automatically from a small set of known sources. An answer about a confidential contract has a different risk profile. Choose according to the data and the reader's need, rather than carrying one permissive rendering configuration into every context.
Even an allowed host is not enough by itself. A shared host may contain other users' uploads or paths that redirect elsewhere. Resolving a valid asset ID to a fixed resource gives the model less freedom than accepting an entire address. Do not append arbitrary model-written parameters to an otherwise approved path and assume the original approval still describes the request.
An image proxy can remove direct contact between the reader's browser and the image host. GitHub's Camo documentation describes hiding browser details this way, while warning that someone receiving an anonymized media URL may be able to view it. Anonymizing a reference is not the same as authenticating its viewer.
If the original external address contains private data, a proxy requesting that address still transmits it. The release decision must happen before the proxy's fetch. Resizing or sanitizing the returned image does not undo a request that has already reached its recipient.
Moving retrieval to a server also introduces a server-side boundary. Our URL-fetching guide explains why a public fetcher should not inherit private-network reach or application credentials. Those controls are prerequisites for the proposed retrieval path, not permission to retrieve anything the model describes as an image.
The stored derivative needs an access and retention policy too. A long public address is not a substitute for viewer authorization. Decide who can retrieve the cached copy, how long it remains and what deletion or access revocation means. A cache must not become a back door to a resource that the user can no longer access through its normal route.
The implementation invariant is simple: an unapproved image node must never receive a fetch-capable source, even briefly. Parse the answer, identify proposed effects, apply policy and only then construct authorized elements. Mounting an image and removing it a moment later may be too late.
For streamed output, show inert text or hold effectful elements until they are complete and checked. Reviewing only the final answer misses the period in which intermediate content may already have initiated a request. A later revision that removes the address cannot retract that earlier contact.
Add an independent browser constraint where appropriate. MDN's img-src reference describes how Content Security Policy restricts image sources and falls back to default-src when img-src is absent. This browser boundary does not configure the server-side proxy or establish the user's right to a particular image. Use it alongside, not instead of, the application decision.
Carry the rule into exports. A chat interface can refuse external images while a PDF generator, email composer or preview service fetches them again. Give each route an owner and identify the point at which authorization is enforced. Our output-release guide addresses the wider decision about the final content and its recipient; rendering is one place where that decision needs concrete enforcement.
Consider a hypothetical support answer containing four elements: an explanation, a product photograph from company storage, a link to a public manufacturer manual and a chart with a new address proposed by the model. This example illustrates the policy; it is not a test of a deployed system.
The application displays the explanation. Its server resolves the photograph's identifier to the correct product and checks the user's entitlement. It shows the manual link with a recognizable destination, without quietly fetching it to build a more attractive card. The proposed chart remains a clear placeholder: “External image not loaded.”
If the reader needs the chart, a vague “Continue?” prompt is inadequate. Make the destination, the contact being authorized and the outgoing information understandable. Where organizational policy prohibits disclosure, user confirmation does not override that prohibition. Generating a chart inside the application from permitted data may be a better route.
Success here does not mean removing every useful image. The permitted photograph works, the prose remains readable and the source link survives. What disappears is the model's authority to cause an arbitrary request merely by placing it in an answer. The tradeoff is less convenience and sometimes an explicit image-admission step, in return for deciding who receives information before sending it.
For a controlled test, use zero unauthorized requests as the proposed acceptance criterion—not zero broken images or zero rendering errors. This is a test target, not a security guarantee or a measured ZharfAI result. Use synthetic data and team-controlled destinations; never place real secrets in test fixtures.
| Fixture | Expected result |
|---|---|
| Unapproved external image in a completed answer | No image retrieval; understandable placeholder |
| The same reference during streaming | No unauthorized request at any intermediate state |
| Ordinary link with automatic preview enabled | Preview retrieval follows the same authorization policy |
| Valid asset identifier belonging to another user | Access denied despite a syntactically valid identifier |
| Approved path redirecting to an unapproved destination | Stop before contacting the next destination |
| Conversation converted into a report or email | The new output path preserves the restrictions |
Record blocked attempts, decision reasons, policy versions and internal event identifiers. Do not copy complete data-bearing addresses into broadly accessible diagnostic logs. Logging can otherwise create another unintended recipient of the same sensitive information. Keep investigation access narrow and retention proportionate.
Repeat the tests after changes to the renderer, plugins, cache, hosting domain or preview builder. Also track legitimate image use and complaints about blocked content. A control that routinely pushes users toward workarounds is not a sustainable design. Provide a clear admission path for needed media rather than restoring arbitrary fetching. The final question belongs before display: what request will this picture make, to whom, and under whose permission?
This is a standard practical Blog guide. The architecture, tables, support example and acceptance criterion are ZharfAI analysis, not customer evidence, an audit of this website or a verified security guarantee. Sources represent OWASP, the remark project, Mozilla and GitHub. Living documentation without an explicit publication date is identified by the review date rather than an invented release date.

A valid export can still turn untrusted text into a spreadsheet formula. Choose explicit cell types, a known import path and tests that preserve data without granting it execution.
Read More
Separate signature checks, durable receipt and permission to act. A practical webhook admission design keeps repeated deliveries from becoming fresh AI workflow requests.
Read More
Repeated JSON keys can disappear before validation begins. Reject ambiguity at the raw-input boundary and keep reviewers and executing tools on the same accepted data.
Read MoreIf you want the agents and automation in this guide working for your engineering team or business processes, start with a small pilot you can measure.