writing/blog/2026/07
BlogJul 26, 2026·6 min read

AI Chat Share Links: The Leak Nobody Audits

Shared AI chats keep turning up in Google. The same architecture flaw hit ChatGPT, then Claude, twice. Why share links leak, and how to build them safely.

On 26 July 2026, developers on X began posting site: search queries that returned pages of shared Claude conversations. According to those reports, the results included API keys, credentials, crypto wallet details, resumes with names and phone numbers, internal company project notes, and a lawyer working through an ethics problem. Anthropic had not yet commented at the time of writing, and the scale of the exposure has not been independently verified.

If that story sounds familiar, it should. In August 2025, Fast Company found thousands of shared ChatGPT conversations in Google results, and OpenAI killed its "make this chat discoverable" option within days. In September 2025, Forbes reported that Google had indexed just under 600 shared Claude conversations — despite Anthropic blocking crawlers in robots.txt.

Three incidents, two vendors, one year. That is not a vendor problem. That is a design pattern that leaks by default, and almost every team shipping an AI product in 2026 has built one.

Every AI chat product ships the same feature. A user clicks Share, the app mints a URL, and anyone holding that URL can read the conversation. It is the cheapest possible sharing model: no accounts, no ACLs, no invitations. Product teams love it because it converts — a shared chat is a free acquisition channel.

The problem is the mental model it creates. "Anyone with the link" sounds like a private link you control. Users read it as unlisted. The system actually implements public, just undiscovered. The gap between those two readings is where every one of these incidents lives.

Undiscovered is not a security property. It is a temporary condition, and at least four forces erode it:

  • Referrer leakage. A user opens their share link, clicks an outbound link on the page, and the destination site's analytics record the share URL in the Referer header. That URL now sits in a third party's logs — and in some analytics products, in a UI that gets crawled.
  • Social and paste-site propagation. Links posted to X, Discord, Reddit, Stack Overflow, or a public Pastebin become crawlable inbound links. This is Anthropic's stated explanation for the 2025 incident, and it is a real mechanism — but it only explains how crawlers found the pages. It does not explain why the pages were servable to them.
  • Browser and extension telemetry. Toolbars, "AI assistant" extensions, and some mobile browsers ship visited URLs to backend services. Several SEO datasets have historically been built this way.
  • Enumeration. If share tokens are sequential, short, or derived from a timestamp, they can simply be guessed.

robots.txt defends against none of these. It is a request to well-behaved crawlers, not an access control, and it does not remove a URL that is already in an index. Anthropic did the polite thing and still ended up in Forbes.

Why the fix keeps getting missed

The reason this bug recurs is that it sits in the seam between three teams. Product owns the share button. Frontend owns the page. Infrastructure owns the headers. Nobody owns "is this page indexable," so it defaults to yes.

It is also nearly invisible in testing. A share page works perfectly in QA, in staging, and on launch day. The failure only manifests weeks later, in someone else's index, discovered by a stranger running a site: query. There is no failing test, no error rate, no alert — which is exactly why it survives to production and stays there.

If you are shipping a share feature — for an AI chat, a report, a dashboard, a generated document — here is the checklist that actually holds.

1. Block indexing at the header, not just robots.txt

robots.txt prevents crawling. X-Robots-Tag prevents indexing, and it works even when a crawler reaches the page through an inbound link it discovered elsewhere. Set it at the edge so no route can forget it:

// next.config.js — applies to every share route, no per-page opt-in required
module.exports = {
  async headers() {
    return [
      {
        source: '/share/:path*',
        headers: [
          { key: 'X-Robots-Tag', value: 'noindex, nofollow, noarchive, nosnippet' },
          { key: 'Referrer-Policy', value: 'no-referrer' },
        ],
      },
    ]
  },
}

The Referrer-Policy: no-referrer line is doing quiet, important work: it stops the share URL from being handed to every site the reader clicks through to.

Add the meta tag too, for renderers that only see HTML:

// app/share/[token]/layout.tsx
export const metadata = {
  robots: { index: false, follow: false, nocache: true },
}

2. Make tokens unguessable

Use at least 128 bits of cryptographic randomness. Never derive the token from the conversation ID, the user ID, or a timestamp.

import { randomBytes } from 'node:crypto'
 
// 32 base64url chars, ~192 bits of entropy — not enumerable
export const createShareToken = () => randomBytes(24).toString('base64url')

3. Expire by default

The single highest-leverage control. A link that dies in 30 days cannot leak in month six. Default to an expiry, make permanent an explicit choice, and show the expiry date in the share dialog so the user understands what they are creating.

create table share_links (
  token         text primary key,
  conversation  uuid not null references conversations(id) on delete cascade,
  created_by    uuid not null references users(id),
  expires_at    timestamptz not null default now() + interval '30 days',
  revoked_at    timestamptz,
  view_count    int not null default 0
);

This is the control that would have mattered most in the reported incident. Before a share link is created, run the conversation through secret detection and warn the user about what they are about to publish. Treat it as a blocking, informed-consent step, not a toast notification.

const SECRET_PATTERNS = [
  { label: 'AWS access key',    re: /AKIA[0-9A-Z]{16}/ },
  { label: 'Private key block', re: /-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----/ },
  { label: 'Bearer token',      re: /\b(sk|pk)-[A-Za-z0-9]{20,}\b/ },
  { label: 'JWT',               re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\./ },
]
 
export function findSecrets(text) {
  return SECRET_PATTERNS
    .filter(({ re }) => re.test(text))
    .map(({ label }) => label)
}

Pair the regex layer with an entropy check for high-randomness strings that no pattern list will catch, and surface the findings inline: "This conversation appears to contain an AWS access key. Publishing it will make that key readable by anyone with the link."

5. Give users a revocation surface they can find

Every incident write-up ends with the same instruction: go to settings, find shared chats, delete the ones you regret. That page needs to exist, be reachable in two clicks, list every live link with its creation date and view count, and support revoke-all. Users cannot clean up exposure they cannot see.

6. Make revocation actually remove the content

Deleting the row is not enough once a page has been cached or indexed. A revoked link should return a hard 410 Gone, and your operations runbook should include submitting removals through Google Search Console and Bing Webmaster Tools. Write that runbook before you need it.

7. Add the regression test

The reason this bug recurs is that nothing fails when it is present. Fix that:

test('share pages are never indexable', async () => {
  const res = await fetch(`${BASE_URL}/share/${knownToken}`)
  const robots = res.headers.get('x-robots-tag') ?? ''
 
  expect(robots).toContain('noindex')
  expect(res.headers.get('referrer-policy')).toBe('no-referrer')
})

Ten lines in CI, run on every deploy. That is the entire difference between a working feature and a Forbes headline.

What enterprises should do this week

If your organisation uses AI assistants — and in 2026 it does, whether sanctioned or not — the share link is an unmonitored egress path. It bypasses your DLP, your proxy, and your email gateway, because it is just a user clicking a button in a browser tab.

Three concrete moves:

  1. Audit what is already out there. Run site:claude.ai/share, site:chatgpt.com/share, and the equivalents for every assistant your teams use, scoped to your company name, product names, and internal domains. Do this today, before the indexes are cleaned and you lose the ability to see what was exposed.
  2. Write the policy in the tool, not the handbook. Enterprise plans on the major assistants let admins disable sharing or restrict it to inside the organisation. A policy nobody can enforce is a wish; a disabled toggle is a control.
  3. Treat pasted secrets as rotated. If a credential appeared in a conversation that was ever shared, rotate it. The cost of rotation is an hour. The cost of assuming it was fine is unbounded.

For teams building their own AI products, the wider lesson connects to a theme we keep returning to in our work on AI agent security and zero-trust architecture and enterprise AI governance: the dangerous surface is rarely the model. It is the ordinary web plumbing wrapped around it, built by people who were thinking about conversion rates rather than crawlers.

The one-line lesson

Three incidents in twelve months, at two of the best-resourced AI labs in the world, all traceable to the same omission: a share page that was servable to a crawler.

Safe defaults are not a feature you add when a user complains. They are the thing you ship first, because the failure mode is silent, delayed, and irreversible. noindex costs one line. Explaining to a client why their API keys are on Google costs considerably more.


Building an AI product and unsure what your sharing, logging, and retention surfaces actually expose? Noqta runs security reviews of AI application architectures for teams across Tunisia and the Gulf.

Sources: Forbes — Hundreds Of Anthropic Chatbot Transcripts Showed Up In Google Search · Search Engine Land — ChatGPT kills Google-indexable chats · Engadget — OpenAI is removing ChatGPT conversations from Google