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 ListObjects permission 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_length is 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?

  1. 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.
  2. 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_at and 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 →