No public object paths. Ever.
Buckets stay private. Uplint never writes a public ACL, never exposes a bucket URL, and cannot serve an object itself. The only route to bytes is a URL your app asked for.
Uplint is a control plane, not a data lake. Objects are written to buckets you own, read only through URLs your app requests, and every operation is on the record. If you ever want us gone, revoking one credential at your provider ends it.
The security model is an architecture, not a promise. Everything Uplint knows about a file fits in a record; everything the file is stays in your account.
These are not options you can misconfigure. They hold for every file, every tenant, every provider, from the first upload.
Buckets stay private. Uplint never writes a public ACL, never exposes a bucket URL, and cannot serve an object itself. The only route to bytes is a URL your app asked for.
A signed URL is issued only in response to an authenticated call from your code — after your authorisation check has already run. It expires; the default is minutes, the maximum is yours to set.
Every upload, URL, move and delete is appended to the file’s record with the actor and the time. So are refused moves. There is no quiet path.
The control plane is never in the data path. Watch one authorised read: authorisation in your code, a signed URL from Uplint, bytes straight from your bucket, and a URL that dies on schedule.
GET /invoices/42authorise: can this user see invoice 42?your code, your rulesPOST /v1/files/file_8Kx92m/url { expires: 300 }policy check · sign against S3 · append url eventactor + time on the record{ url: "https://…?X-Amz-Signature=…", expires_at }302 → signed URLGET the object — directly from your bucketbytes never pass through Uplint5 minutes later: the URL is deadnothing to leakUplint reaches your buckets only with a credential you issued and can withdraw. That one fact bounds everything else on this page.
You create a credential at your provider scoped to the buckets Uplint may use — nothing else in the account. Uplint stores it encrypted and never shows it again.
Rotate at the provider on your schedule and update the connection. In-flight signed URLs keep working until they expire; the old key is dead the moment you say so.
Revoke at the provider and Uplint is cut off instantly. Your objects are untouched, your buckets are yours, and the record stays as evidence.
The architecture does the heavy lifting. These are the practices around it that an assessor will ask about.
TLS on every hop: your app to Uplint, Uplint to every provider.
Storage credentials are encrypted with a managed key service and decrypted only inside the service that talks to the provider.
Per-environment keys with separate permissions; rotate or revoke from the dashboard, every use logged.
Records, policies and events are partitioned per account; there is no cross-account query path.
SSO and two-factor for the console; role-based access for who can connect storage or change policy.
Found something? security@uplint.dev. We acknowledge within one business day and publish fixes with credit.
On upload, the body streams through Uplint on its way to your bucket and is not retained. On read, it doesn’t pass through Uplint at all — the signed URL points at your bucket and the bytes go straight to the client. Nothing at Uplint ever holds a copy.
There is no object store at Uplint to read from. Reaching an object requires a signed URL, which is only issued in response to your app’s authenticated call and is logged with the actor. Provider credentials are encrypted and used only by the signing service.
Your objects are in your bucket and unaffected. Signed URLs already issued keep working until they expire, because the provider validates them, not Uplint. New URLs cannot be issued during the outage — that is the honest trade-off of keeping the control plane out of the data path.
Your buckets and objects are already yours, readable with any tool. Export the records and events, revoke the credential, and Uplint is gone. There is no migration out because nothing moved in.
We publish our controls rather than lean on a badge; the objects sit under your provider’s attestations, and the controls above are what an assessor sees. Ask us for the current status of independent testing and reports at security@uplint.dev.
Connect a bucket with a credential you can revoke tomorrow, and build on a file layer that never becomes the place your data lives.