Where Your Originals Live
A media library is one of the most personal things you can store in the cloud: originals of your family, your clients, your work. It's also one of the riskiest things a backend can handle — because processing media means parsing attacker-controlled bytes with some of the most complex parsers in computing. Image codecs, video containers, EXIF readers: decades of security advisories trace back to a malformed file meeting a decoder.
So security isn't a feature we bolted onto 5AM. It's a set of principles the pipeline is shaped around. Here's how we think about it.
Media bytes are untrusted input
Every file that reaches us is treated as hostile until proven boring. The practical consequence: decoding never happens in the API server.
The service that holds your session, your billing state, and your database connections does not open your files. Video thumbnailing, format conversion, and metadata extraction run in a dedicated processing service. AI-powered edits run in another. Image-variant generation runs in its own worker. Each is a single-purpose container with the minimum credentials for its one job.
If a malicious file ever finds a parser bug, it detonates inside a container that holds almost nothing — not inside the process that knows who you are.
Uploads that never transit the API
Large uploads use a presigned flow: the API authenticates you, checks your storage quota first, and only then issues a short-lived upload URL scoped to exactly one object. Your bytes then travel directly to storage — the API server never buffers them.
This is usually pitched as a performance feature (it is — no size limits, no memory pressure), but it's a security property too: the most complex, highest-volume data path in the product simply doesn't pass through the most sensitive service. When the upload completes, the client reports back, and processing kicks off asynchronously from there.
Services authenticate each other like strangers
Inside the platform, no service trusts a request just because it arrived. Every internal hop — API to video processor, API to AI editor, processors calling back with results — carries an HMAC-SHA256 signature computed over the raw request body plus a timestamp, with a very short replay window. Signatures are verified against the raw bytes before anything is parsed. On top of that, the processing services are deployed private: the platform itself rejects unauthenticated callers before our code even runs.
The same discipline applies to results coming back. A webhook that says "your video is ready" is cryptographically verified like everything else — a forged callback can't inject data into your library.
Blast radius is a design input
The clearest example of this principle: 5AM can run small AI-generated Python programs for computational tasks. Executing generated code is the kind of feature that deserves paranoia, so it gets layers:
- Static analysis is the primary gate. Generated code is parsed and rejected before execution if it imports process-spawning, networking, or GPU/UI modules, calls
eval-family functions, or reaches for the classic sandbox-escape tricks. - The sandbox is the backup. Code that passes runs with a scrubbed environment, tight CPU/memory/file limits, and a hard wall-clock kill.
- Egress is allowlist-only. Outbound network traffic goes through a proxy that permits only the hosts declared for that request — everything else is refused.
- The service itself is nearly secretless. The executor holds exactly one credential: the key to verify who's calling it. No storage credentials, no AI keys, no webhook secrets. Even a complete sandbox escape lands in a service that can't reach your media.
That last point is the philosophy in miniature: we don't just ask "how do we prevent a breach?" but "what does the attacker get if this layer fails anyway?" — and we design so the answer is "as close to nothing as we can manage."
Tokens that can do only one thing
Broad credentials are how small compromises become big ones, so access is scoped aggressively:
| Credential | What it can do | What it can't do |
|---|---|---|
| CLI access token | Only its granted scopes: read, write, or admin | Anything outside those scopes |
| AI character token | The specific skills enabled for that character, at that character's scope | Other skills; survives ~15 minutes per session token; instantly killable |
| Camera credential | Add photos to one pre-bound album | List, download, or delete anything — or touch any other album |
| Internal service identity | Its one processing job | Hold user sessions or long-lived user credentials |
The camera one is worth dwelling on. Cameras with built-in FTP push are wonderful and their credential storage is… camera-grade. So each camera gets its own credential bound to exactly one album, exchanged at login for a short-lived, album-scoped session token. If a camera is stolen off a tripod, the attacker can add files to that one album. That's the entire blast radius.
AI characters follow the same logic: each has its own token, its own enabled skills, and a kill switch that deactivates the token at the platform layer in seconds.
Storage that defaults to private
Nothing in your library is publicly addressable by default. Buckets are private; media is served through authenticated routes that check access on every request — including range requests for video streaming. Sharing is always an explicit act with an explicitly scoped result: a direct share to a specific account, an email invite that expires if unclaimed, or a public link you deliberately enable and can revoke.
Two smaller details we consider part of storage security:
- Quota integrity. Storage accounting is charged only after an upload actually succeeds, and deletions credit back the bytes actually freed — bookkeeping that stays honest even when operations fail halfway.
- Content-hash dedup. Retried uploads (a camera re-pushing after a dropped connection, a script run twice) are recognized by content hash instead of creating duplicate copies.
Honest limits
No writeup like this is credible without the other half: sandboxes mitigate rather than eliminate; an egress allowlist controls where traffic goes, not every byte of what is said to an allowed host; and parser isolation reduces blast radius rather than making decoder bugs impossible. Security here is layers that each assume the others can fail — not a claim that any single layer is perfect.
That's also why the architecture is built to keep improving without breaking you: scoped tokens can be rotated, processing services can be rebuilt and redeployed independently, and every version of the CLI verifies its own downloads against published hashes.
What this means for you
Upload the originals. Share deliberately. Revoke freely. The pipeline underneath was designed by asking, at every hop, "what's the worst thing these bytes could be?" — and making sure the answer stays small.
If you're security-minded and spot something we should look at, we genuinely want to hear from you — reach out through 5am.app. And if you want to see the scoped-token model in action, the CLI is the fastest tour: mint a read-only token and notice how much of the platform politely refuses to move.



