The Claude Code WebSearch Black Box
November 27, 2025Absolutely nothing new here, move along, this is well known, but I didn’t know it and it was semi-interesting to look into the details of how one small part of one of these Agentic Coding Computers (tm) work. So I wrote a few notes as I explored.
In particular, I was investigating how Anthropic’s WebSearch tool works when the tool calling magic decides to go out and query the web for info before proceeding. There are lots of details on the official Claude Docs site but the summary is that you end up with a search_result object.
{
"type": "search_result",
"source": "https://example.com/article", // Required: Source URL or identifier
"title": "Article Title", // Required: Title of the result
"content": [ // Required: Array of text blocks
{
"type": "text",
"text": "The actual content of the search result..."
}
],
"citations": { // Optional: Citation configuration
"enabled": true // Enable/disable citations for this result
}
} Ah cool, I can see what I’m burning up tokens on in the text field. Nice.
Hold on! I’m actually getting a web_search_tool_result back, not a search_result, and these objects in Claude Code contain almost the same stuff but not quite:
- title - page title
- url - the source URL
- encrypted_content - encrypted page content (not meant for you to read)
- page_age - when the page was last updated
Example:
{
"type": "web_search_tool_result",
"tool_use_id": "srvtoolu_01WYG3ziw53XMcoyKL4XcZmE",
"content": [
{
"type": "web_search_result",
"url": "https://en.wikipedia.org/wiki/Claude_Shannon",
"title": "Claude Shannon - Wikipedia",
"encrypted_content": "EqgfCioIARgBIiQ3YTAwMjY1Mi1mZjM5LTQ1NGUtODgxNC1kNjNjNTk1ZWI3Y...",
"page_age": "April 30, 2025"
},
{
"type": "web_search_result",
"url": "https://example.com/another-page",
"title": "Another Result",
"encrypted_content": "...",
"page_age": "May 1, 2025"
}
]
}
It’s always an encrypted_content field. Never a text field. Which made me wonder what I’m supposed to do with it?
Answer: I don’t do anything with it. I (or this case Claude Code on my behalf) simply pass it back to Claude in subsequent turns of a multi-turn conversation. Claude uses this internally to reference the original search content, generate citations, and mostly to maintain context about what was found.
Ok, I get it. So where is the public key stored to validate it? Is there a key to decrypt it hiding somewhere? I couldn’t find either. Because it’s not in the client, dummy! Of course..
The encryption is entirely server-side:
- Anthropic’s servers fetch web content
- Anthropic encrypts it before sending to you
- You pass the opaque blob back in subsequent requests
- Anthropic decrypts it on their end
You never decrypt anything. There’s no public key exposed to you, no client-side crypto, nothing to validate. The encrypted_content field is a black box by design.
The Security Model
Upon reflection this makes perfect sense (see Why? below). But it’s useful to write out the consequences of what we’re dealing with:
- You’re trusting Anthropic’s infrastructure entirely
- The “encryption” is essentially a signed/encrypted token that only Anthropic can read
- You can’t verify the content wasn’t tampered with
- You can’t verify what’s inside (or compare it to the cited source)
- You can’t verify the crypto is sound
- You just pass blobs around and trust Anthropic
Of course the entire bloody LLM takes this shape as well, and you’re trusting that with far less insight into its inner workings. But for some reason not even being able to see the content of a web search struck me harder.
Alternative Methods
If you need to audit/verify what content is being used in your AI pipeline, you’d need to:
- Fetch the URLs yourself - You can scrape/fetch those URLs independently to see what content likely came from them. But you can’t compare it to what the model injested.
- Ask Claude to summarize what it found - In your prompt ask Claude to explicitly quote or describe the search results it’s using.
- Use your own RAG instead - If you need full control over context, skip web_search and its tool variant and implement your own search + retrieval pipeline. Good times!
Obviously this is all doable if you’re building your own agentic coding magic machine to compete with Claude Code, but as simple end users of CC it’s just how it works we either don’t use the tool or live with it. I haven’t checked any other products but I assume they all work the same way.
Why Encrypted
As anyone who’s used this stuff would already know, the encryption used here is a business/legal decision, not a technical one. The reason it works like this, I would assume, is:
- Licensing/Copyright - Anthropic uses Brave Search as the provider. The encryption prevents you from using Claude’s API as a free web scraping service to extract content from websites.
- Content provider agreements - Publishers likely only allow their content to be used for AI context, not redistributed in raw form.
So yes, you’re paying for tokens you can’t inspect but I can’t see how they can work around this without opening up a world of scraping abuse (as if that’s not already a rampant problem..).
My lesson learned? Learning new things is fun! Be curious about how things work! I now know just a little bit more about how these new agentic coding tools works, and there’s a ton more info in the WebSearch documentation about things like user flows that were helpful to broaden my knowledge. I feel like this quick sidequest might not have been a total waste of time. Heh.