What flipped
The gap between "I wrote this" and "this is at a URL" used to contain a human decision. Now it contains a tool call. Removing the pause removes the moment where somebody would have noticed that the report has a customer's email addresses in it — so the safe state has to be the default state, not a setting the caller remembered to pass.
What private-by-default actually requires
Four things, and skipping any one of them makes the other three decorative:
- Entropy in the URL. 22 characters from a 62-symbol alphabet is on the order of 1039 possibilities. Enumeration is not the threat model.
- No referrer. The token is the credential, so it must not travel in a
Refererheader to whatever the page links to. - Not indexed, not trained on.
X-Robots-Tag: noindex, noai, noimageaion every viewer response, plus arobots.txtthat keeps well-behaved crawlers from fetching viewer paths at all. - Real gates when the URL is not enough. A shared passphrase, a work-email domain gate, a one-time link, or end-to-end encryption where the key never leaves the fragment.
The threat is not guessing, it is forwarding
Nobody brute-forces a 128-bit token. Links leak the boring way: forwarded into a group chat, pasted into a ticket, captured in a screenshot, or handed to a link-preview bot. That is why the interesting controls are the ones that survive forwarding — an email gate makes the new recipient verify, a one-time link is already spent, and expiry closes the window.
The CSP corollary
If the host serves whatever bytes it is given, a careless <script src>
in agent output can exfiltrate what the page contains. Every viewer response carries a strict
Content-Security-Policy: no third-party script origins, no eval. It applies to
SVG opened as a document too, which is what makes byte-for-byte SVG hosting safe without
rewriting the file.
The deletion corollary
"Expired" has to mean gone. An expired link answers 410 immediately, and a
scheduled purge then deletes both the database row and the stored object, after which the
same URL answers 404. Two codes on purpose: the first says this existed and
is over, the second says nothing at all.
What it costs the author
Almost nothing, which is the point. The defaults on this deployment are:
| Default | Value |
|---|---|
| Visibility | Unlisted. The URL carries a 22-character random token; nothing is listed publicly. |
| Expiry | 7 days for a keyed publish, 24 hours for an anonymous one. Pass never to keep it. |
| After expiry | The row and the stored object are both deleted by a scheduled purge, not just hidden. |
| Robots | X-Robots-Tag: noai, noimageai, noindex on every viewer response. |
| Referrers | Referrer-Policy: no-referrer, so the token never leaks into someone else's logs. |
| Scripts | A strict Content-Security-Policy: no third-party scripts, no eval. |
| Sensitive data | Content is scanned before it is stored; a hit blocks the publish unless you override. |
| Transport | HSTS with a long max-age; the viewer is HTTPS-only. |
Verify it rather than believe it
Publish anything and read the headers off the viewer URL:
curl -sI https://read.botook.ai/s/YOUR_TOKEN | grep -iE 'robots|referrer|content-security'Is an unguessable URL really access control?
It is capability-based access control: the link is the credential. That is genuinely enough for a lot of sharing, and genuinely not enough when the link will be forwarded — which is why passwords, email gates, one-time links and encryption exist on top of it.
Can I make a page public on purpose?
Yes. Public is a choice you make per link rather than a state you have to climb out of.
Does noai actually stop anyone?
It is a request, not a fence — the same status as robots.txt. The fence is that
the URL is unguessable and the page can be gated. Sending the header costs nothing and
removes the excuse.
What can the host itself read?
Everything, unless you use end-to-end encryption, in which case the browser encrypts before upload and the key stays in the URL fragment — which browsers never send to a server. Then the stored bytes are ciphertext to the host too.