Guide
What an upload link can and can't do
A precise inventory of what a pre-signed `upload.create_link` URL grants — and what's deliberately out of scope.
5/18/2026 · connect0 · 2 min
A pre-signed upload link is the narrowest possible capability for connecting a file into the core — here's exactly what it grants.
A pre-signed URL is a capability — and the smallest one we could ship. Here's a precise inventory.
What it grants
- One PUT to one specific object key in one specific R2 bucket.
- One specific content-type (signed into the URL via the SigV4
signableHeaders). - (Optionally) one specific byte count (if the agent passed
content_length). - Valid for a bounded TTL — default 15 min, max 1 hour.
That's it. No reads, no listing, no deletes, no other paths, no other buckets.
What it doesn't grant
- Reading the uploaded file later. R2 is private; the sandbox reads via the FUSE mount under prod-mcp-sa's R2 credentials, not via a pre-signed GET.
- Listing the bucket. No
ListObjectspermission attached. - Cross-project writes. The key is scoped to
projects/<this-project-id>/.... Even if the same R2 keys back another project, that project's keys can't be touched. - Deletes. R2 keeps the object until something writes over it or the project is hard-deleted.
- Larger files than declared. When
content_lengthis signed in, even one extra byte returns 403.
What an attacker gets if it leaks
The most-believable bad scenario: the agent prints the URL in a long output that ends up in a Slack channel that's later compromised. What does the attacker do?
- PUTs garbage to the target key. Effect: overwrites the file the legitimate user was about to upload. Discovered immediately because the user's PUT will then 403 (URL is one-shot) and they'll re-issue.
- PUTs malicious content that the agent later reads. Effect: only if the agent was already going to read the file and act on it without verification. Worst-case shape but still bounded — the file is one specific path under
/workspace/.
Both are bounded by the TTL. The longer the link is valid, the bigger the window.
Why we don't ship "broader" links
A "PUT anything anywhere in /workspace for an hour" link would be more convenient. It's also a much bigger blast radius if leaked. The narrowness of upload.create_link is the security model.
If you genuinely need "the agent writes lots of files," use upload.write (each call is a fresh, server-side-authorized write) or sh (in-sandbox writes that don't need a separate capability at all).
Rotation and revocation
- Rotation. The R2 access keys themselves can be rotated; the existing pre-signed URLs become invalid the moment the credentials change. No need to explicitly revoke individual links.
- Revocation of a single link. Not supported. The URL stops working at
expires_atand otherwise can't be revoked individually. Set short TTLs.
Next steps
Where this fits
This is the Connect everything pillar of connect0 — the core that connects everything your company runs on. Upload links are how data connects into the core without ever widening the blast radius. Start building → · All guides →