[DOCS] Logical Inconsistency in Web Fetch Tool Security and URL Validation Logic

Resolved 💬 3 comments Opened Jan 17, 2026 by coygeek Closed Feb 28, 2026

Documentation Type

Unclear/confusing documentation

Documentation Location

  • URL: https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool

Section/Topic

  • Section: Web fetch tool -> URL validation and associated Warning block regarding exfiltration risks.

Current Documentation

The documentation currently contains the following two statements:

Warning Block: "To minimize exfiltration risks, Claude is not allowed to dynamically construct URLs. Claude can only fetch URLs that have been explicitly provided by the user or that come from previous web search or web fetch results."

And under the URL validation section:

"For security reasons, the web fetch tool can only fetch URLs that have previously appeared in the conversation context. This includes: ... URLs from previous web search or web fetch results."

What's Wrong or Missing?

There is a logical contradiction between the security goal (minimizing exfiltration by preventing dynamic URL construction) and the functional implementation (allowing Claude to fetch URLs found in search results).

  1. Dynamic Selection vs. Construction: If a web_search returns 100 links and Claude "decides" which one to fetch based on its own reasoning, it is effectively performing dynamic selection. If the model can select a URL from a list it generated via a search query, the "minimization of exfiltration risk" is weakened, as the model could theoretically search for an attacker-controlled endpoint and then "fetch" it.
  2. Definition of "Explicitly Provided": The term "explicitly provided by the user" is contradicted by the subsequent clause allowing URLs from "previous web search results." A URL found in a search result was not explicitly provided by the user; it was discovered by the agent.
  3. Confusion on Limits: It is unclear if Claude is blocked from string concatenation to form a URL (e.g., https://attacker.com/ + secret_data) or if it is blocked from selecting any URL that wasn't already in the transcript. If it can select from search results, the "exfiltration protection" needs a more technical explanation of how it prevents the model from leaking data to those found URLs.

Suggested Improvement

Clarify the "Source Trust" hierarchy and distinguish between URL Construction and URL Selection.

Suggested Revised Text for the Warning Block:

"To minimize exfiltration risks, Claude is restricted from constructing new URLs (e.g., through string manipulation or concatenation of sensitive data into a URL path). Claude can only use the web_fetch tool on URLs that already exist within the conversation context, such as those provided directly by the user or those returned as verbatim strings from a web_search call. This ensures Claude cannot 'encode' data into a newly created URL to leak information."

Suggested addition to URL Validation:

"Note: While Claude can fetch URLs found in search results, it cannot modify those URLs. For example, if a search result returns example.com/page, Claude can fetch that exact string, but it cannot attempt to fetch example.com/page?data=[stolen_key]."

Impact

High - Prevents users from using a feature

Additional Context

  • Links to related documentation: [Computer Use Security](/docs/en/agents-and-tools/tool-use/computer-use-tool#security-considerations) also mentions prompt injection/exfiltration risks, but has different guidance.
  • Example: In a RAG (Retrieval-Augmented Generation) workflow, if an attacker-poisoned search result contains a URL, the current documentation suggests Claude is "safe" because it didn't "construct" the URL, but it might still "fetch" it, potentially triggering a GET request that leaks context (IP address, user-agent, or specific headers) to the attacker. Clearer documentation on what constitutes a "constructed" vs. "discovered" URL is vital for security-conscious developers.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗