Loomwork · № 012
How I handle credentials in an agent platform
·6 min·Loomwork

Patient work, woven in public.
This is Thread 12 of Loomwork. New here? Thread 01 explains why this newsletter exists — 2 minutes.
The scariest moment in an agent platform isn't the AI. It's the text box that asks for a token.
To watch your GitHub, an agent needs a GitHub token. To watch your Vercel, a Vercel one. Which means at some point you paste a credential into software someone else wrote — and you have to decide whether you trust where it goes. So when I designed the vault that holds those secrets, I didn't build it around "don't get breached." Everyone says that; nobody can promise it. I built it around a harder, more useful question:
The day someone does get in — and you should always design as if they will — what do they actually walk away with?
Assume the breach, then make what they hold worthless. That single reframe is the whole design, and it's worth walking through the way I actually did it: one layer of compromise at a time.
Assume the breach — layer by layer

They read your application logs. They get nothing. A token's plaintext is never written to a log, an error message, or an API response. The only thing the system ever emits about a stored token is its last four characters, for display (…a1c9) — enough for you to recognise it, useless to anyone else.
They walk off with a full copy of the database. The classic worst case — and still nothing usable. Every credential is ciphertext, and the key that unlocks it is not in the database. It lives in the application's environment, a separate system. The store holds locked boxes; the key sits somewhere else entirely. A database dump is a pile of locked boxes with no key in the pile.
They tamper with a stored value. It fails closed. Each credential is sealed with AES-256-GCM, whose authentication tag means a modified ciphertext refuses to decrypt rather than quietly returning corrupted bytes. You get a hard error, not silent garbage an agent might act on.
They want the plaintext to keep. There's no moment to grab. Nothing in the product ever decrypts a token to show it — not to the user, not to me. Decryption happens only server-side, in the instant an agent actually uses the token, and the plaintext is discarded immediately: never logged, never returned, never persisted in the clear.
Each answer covers the layer beneath it. The value of running this exercise before launch, rather than reconstructing it after an incident, is that the architecture falls out of it — you build the thing the threat model demands, not the thing that's easiest to wire.
The primitives are deliberately boring
Boring is the compliment in cryptography — novelty is where bugs live. The building blocks behind those answers are the standard, well-worn ones:

- AES-256-GCM, the standard authenticated cipher, with a fresh random IV on every write — so saving the same token twice produces different ciphertext, and there are no patterns to mine.
- The key never lives with the lock. Application environment, not the database. Two systems, not one — so compromising either alone isn't enough.
- Read-only by default. Every credential is stored with read scope only. An agent can see your GitHub or Vercel; it cannot push, merge, deploy, or delete. Write access is a separate, deliberate decision with its own approval flow — that's next week's thread.
- Or bring your own key. For the model itself, you can supply your own Anthropic key, sealed exactly the same way. Your custody.
The decision that actually mattered
The interesting part of a credential design isn't the cipher — everyone reaches for AES-GCM. It's where the key lives, and I had three real options:
- Let the database encrypt it (a managed vault feature). Simplest to wire — and it puts the lock and the key inside the same system, the exact thing a database-level compromise takes in one motion. Rejected: it collapses the separation that makes a database dump worthless.
- Application-level encryption, key in the environment — what I built. The store and the key are split across two systems, so one being breached isn't enough to read a single token. For where this product is today, that's the right blast-radius trade-off.
- Envelope encryption with a managed KMS — a per-tenant data key wrapped by a key that never leaves a hardware boundary, so no single key is ever a systemic dependency. This is the bar for regulated data or a large multi-tenant surface. It's more moving parts than my current stage warrants — but it's the architecture I'd move to the moment the threat model changes, and I know precisely what would trigger that move.
Naming the option you didn't take — and the condition under which you'd revisit it — is most of what "senior" means in a design review. A vault isn't a checkbox; it's a position on a curve, and the discipline is knowing exactly where you're standing on it and why.
Where it goes next
Rotation is designed in from the start: the ciphertext is versioned and the vault carries a two-key ring, so the master key can be rolled forward without downtime. Turning that into a one-command, scheduled operation is the operational tier I'm building next — alongside the rest of credential-lifecycle maturity you layer in as the surface grows. It's deliberately staged: build the cryptographic core to the right bar first, then the operational tooling around it, rather than doing everything half-way at once.
The claim here isn't "this is unbreakable." Nothing is, and anyone who tells you otherwise is selling something. It's that handing your stack to an agent platform is a real act of trust, and the least I owe you is a precise, layer-by-layer answer to what happens to what you hand me — including the day someone tries to take it.
Security you can explain to the layer beats security you hope holds.
— Vamshi
Loomwork is by Vamshi Krishna Veggalam. Building Foundry at mindloomhq.com, with the full archive at loomwork.dev. Find me on LinkedIn.
This thread first ran on LinkedIn on July 12, 2026 — the conversation is over there. Read it on LinkedIn and join the thread
