Deniability infrastructure for AI agents
We built deniability infrastructure for AI agents. The construction is open source and free for any use, proprietary or otherwise. Every consumer surface is free. The hosted product is for engineering teams holding many users' secrets at scale. Here is why that shape, what it does, and how to check us.
The class of problem is older than the agent boom but the agent boom is what made it urgent. Behind every consumer-facing AI agent (inbox assistant, coding agent, customer-support bot, AI accountant) sits a database of OAuth tokens, API keys, and refresh tokens for thousands of customers. The agent has to be able to read them: that is the whole point. The attacker who lands a well-aimed prompt injection on that agent also gets to read them. Once. All of them. The standard secret managers (AWS KMS, HashiCorp Vault, 1Password, Doppler) protect the bytes from outsiders. None of them have an answer for an authenticated agent that has been talked into reading its own context aloud.
deny.sh changes the shape of that game. The same ciphertext decrypts to completely different content depending on which control file you feed back in. The passwords don't change between the two decrypts; the control file is the part that decides what comes out. One control file reveals the real thing. A second reveals a plausible decoy. Both are valid plaintexts. The bytes don't tell the attacker which is which, because cryptographically, they can't. Hand the agent the decoy bundle: shape-correct OpenAI keys, AWS credentials, Stripe secrets, JWTs, recovery phrases. When the injection lands and the agent surrenders its context, what surrenders is a decoy. The real credentials live behind a control file the agent was never handed.
And here is the part that turns a defensive trick into an alarm system: every decoy is also a tripwire. You hash it once and arm it. The moment that byte string is touched at a deny.sh decrypt endpoint, we fire a critical event into the audit chain before the response even returns, and fan it out to your Datadog, PagerDuty, or Slack in about five seconds. The breach stops being the thing you find out about in a quarterly review and becomes your earliest detection signal. The attacker walks away with a fake credential, and you get paged the instant they try to use it.
Think of a safe with two combinations. One opens a compartment with a small float of cash, an old phone, some stale notes. The other opens the real compartment underneath. Whoever forces the safe and tries the first combination they find walks away thinking they got everything. They didn't.
That trick is the wedge. The product around it is deniability infrastructure with two layers that map onto two buyer types:
- Agents Infrastructure ($999/mo, hands-on onboarding). The hosted runtime that engineering teams shipping AI agents run on. Per-tenant key isolation, per-tenant scoped audit log, signed webhooks, SAML SSO, BYOK under your AWS KMS CMK, named SLA. The construction underneath is the same primitive in the free SDK; the value on top is the multi-tenant operational discipline you don't want to build yourself.
- Free SDK, CLI, browser tools. Apache 2.0, every line on GitHub.
npm install deny-sh,pip install deny-sh,cargo add deny-sh, plus the Go module. Drop it into anything, proprietary or open, with no copyleft surface. For individual builders, single-file encryption, seed-phrase protection, the Telegram bot, the Chrome extension, all free forever.
The construction in the middle is the same one in both layers, and we publish it in full. /security walks the five-step algorithm primitive-by-primitive. /threat-model names every assumption. /verify ships a 22-test browser verification suite. The whitepaper has the formal version. We do not want you to trust this; we want you to check it.
The longer argument for why deniability needs to be infrastructure rather than a library lives in a separate post. This one is the launch.
Beyond AI agent platforms, the same primitive lands cleanly on adjacent buyers we did not optimise for but who happen to need exactly this shape:
- Crypto custody. Exchanges and custodians sit on hot-wallet keys for customer withdrawals. Historically, a breach means everything leaves at once. With deny.sh, what leaves is a decoy wallet.
- Healthcare. PHI stores where HIPAA breach safe-harbours give partial protection if the data was "encrypted to the standard." Deniability sits above that line. Even when the file leaks, what the attacker reads is a decoy.
- Security teams. Your breach playbook is the single most sensitive document in the company. If the attacker reads it during the breach, every defensive move you make is one they're already ahead of. Deniability keeps the playbook usable after compromise.
For audiences at scale, the algorithm is the smallest part of the problem. Running it safely across thousands of tenants, proving you ran it correctly, and surviving an audit is the rest. That is what the Agents Infrastructure tier is for.
How it works
You encrypt a file with two passwords and a decoy message (write your own, or let the realism engine write one for you). The encrypt operation produces a single ciphertext alongside two small control files: a real control file that decrypts to your real content, and a decoy control file that decrypts to the decoy. The two passwords are the same in both cases; only the control file differs.
When the bytes leak (backup stolen, agent prompt-injected, drive seized, phone lost) the attacker finds your ciphertext and the obvious control file sitting next to it. That control file opens the ciphertext to the decoy. The real control file is somewhere completely separate: a hardware key, a trusted human, a different jurisdiction. The attacker reads the decoy, believes that's everything, and stops looking.
The decoy is the lever. It can be anything plausible: a bitcoin wallet topped up to £150 instead of the £50,000 one the attacker expected, a stale set of API keys, a doctored breach playbook. The realism engine generates believable decoys across 69 credential types automatically (card numbers, recovery phrases, IBANs, JWTs, PEM keys, SaaS API tokens, crypto wallet keys, identity numbers, GCP and Azure keys, more) with each candidate scored against the same validator a real one would pass: Luhn, BIP39, mod-97, NHS Modulus 11, Base58Check, structural checks. Shape-correct in every place an attacker would think to check. A static decoy pool would itself be a fingerprint, so the engine returns different bytes every time. On structured credential types, Honey Mode does the generate-and-arm step in a single call.
No hidden partition, no "deniable section" header, no entropy tell in the bytes. The maths is the maths. It just stops working in the attacker's favour.
The decoy is also a tripwire
A decoy that only sits there and absorbs the attacker's attention is half the value. The other half is that it tells you the moment it was touched. This is the layer the rest of the security stack doesn't have: standard secret managers can't tell you a credential leaked until it's used somewhere you happen to be watching. A deny.sh decoy is its own alarm.
The mechanism is a one-way fingerprint. You take the SHA-256 of a decoy (either the decoy control file, or the decoy plaintext) and register that 32-byte hash with us, with a free-form label. Only the hash and the label ever cross the network. The real bytes never leave your machine. Then:
- controlData tripwires fire before decryption. We match the hash against the control file in the decrypt request, so the wire trips even if the attacker's password is wrong. This is the surface for honeytoken control files you leave where an attacker looks first: a README, a wiki, an S3 prefix.
- plaintext tripwires fire after a successful decrypt, matching the hash of the recovered plaintext. This is what the realism-engine decoy bundles arm: the shape-correct
.envvalues an attacker would phish and try to use.
When either fingerprint shows up at the deny.sh decrypt endpoint, we write a critical event into the tamper-evident audit chain before the response returns, and fan it out to your configured Datadog, PagerDuty, or Slack webhooks in roughly five seconds. Crucially, the decrypt response shape does not change when a tripwire hits, so the attacker can't tell they tripped anything. They believe they got the secret; you already know they didn't.
It scales to the size of the problem. Arming one decoy by hand is a paste into /dashboard/decoy-alerts. Arming a decoy per row across a customer database is one CLI command: deny-sh tripwires arm-bulk --type stripe-live-key --count 1000 generates the decoys, hashes each one, registers them in bulk, and writes you a CSV. One tripwire per row, up to a million rows, so your coverage matches your database instead of your demo. The full mechanics live on detecting prompt injection at scale.
Standard ingredients
Cryptographers, correctly, get twitchy about novel algorithms. Most security disasters start with somebody inventing a clever new cipher that turns out to have a hole in it. deny.sh deliberately doesn't. Three boring, well-studied building blocks:
- Argon2id turns passwords into a key. Deliberately slow and memory-hungry, so an attacker can't throw a GPU farm at guessing.
- AES-256-CTR does the encryption. The same standard your bank, your VPN, and the disk encryption on your phone use.
- An XOR composition glues them together so two different keys produce two different plaintexts from the same ciphertext. The XOR is the only part specific to deny.sh; the security guarantee rests on AES and Argon2id underneath, not on the XOR.
Full algorithm, primitive by primitive, is on the construction page. Every claim is independently testable: open deny.sh/verify and run the 22-test suite. Chi-squared on the output, entropy measurement, fuzz inputs. Runs in your browser, no calls home. Don't trust us. Run them.
The codebase ships under two licences. The SDKs and the MCP server wrapper are Apache 2.0: free to embed in any product, proprietary or open, no commercial licence needed. The application layer (the hosted Agents Infrastructure runtime with per-tenant key isolation, scoped audit log and decoy tripwires, plus the hosted vault) is AGPL-3.0, with a commercial path for proprietary self-hosting. Same split Stripe, Supabase, Auth0, and HashiCorp use. The licensing page walks through it.
How to check our claims
A deniability product gets held to a higher bar. It should. Four trust anchors live alongside the launch, each independently checkable:
- /threat-model: what deny.sh defends against, what it partly defends against, what it doesn't defend against at all. Plain prose, no marketing fog.
- /security: the formal construction. Named primitives, deniability proof sketch, constant-time notes, KAT figures across SDKs for byte-for-byte cross-compatibility. The whitepaper goes deeper.
- /disclosure: coordinated disclosure policy. 48-hour acknowledgement, 90-day window, safe harbour for good-faith research.
security@deny.shis monitored; the PGP key is onkeys.openpgp.org; the metadata is in a clearsigned security.txt (RFC 9116). - /verify: signed git tags, registry integrity hashes, SRI on every served asset with a manifest at
/.well-known/integrity.json, and a reproducible-build recipe.
The verification walkthrough has the concrete commands. An independent third-party cryptographic audit is on the roadmap. Results will be published in full when it lands, good and bad. Until then we're explicit: the deniable composition is novel and unaudited, the primitives underneath are not. If a not-yet-audited composition is too much risk for your threat model, wait for the audit.
What you can do with it today
If you are an engineering team shipping an AI agent with secrets in customer context, the path starts with /agents. Read the pillar page, then email us. Onboarding is hands-on: we want to see your tenancy model and decoy taxonomy before flipping the switch.
If you are an individual builder, easiest path: open deny.sh/encrypt in any browser. Type a message. Pick two passwords. Write a decoy (or flip on the realism engine and let it write one). Get back a ciphertext and two control files (one real, one decoy). Hand either control file plus the same two passwords to a friend. Watch them decrypt the same encrypted bytes to completely different things depending on which control file they used. The whole demo runs in your browser, nothing leaves your machine.
The same primitive ships in a dozen shapes:
- Four production SDKs, ready to drop in:
npm install deny-sh,pip install deny-sh,cargo add deny-sh, plus the Go module atgithub.com/deny-sh-crypto/deny-go/v2. JS SDK core is around 3 KB minified with one runtime dependency (hash-wasmfor portable Argon2id). - A REST API, a CLI, a Chrome extension, a Telegram bot for the cases where installing a library isn't worth it.
Agents-first, including how they find us
Cloudflare scanned the 200,000 most-visited websites on the web. Fewer than fifteen of them had an Agent Skills index. deny.sh is one of them, on day one. If the buyer is an engineering team running agents, the agents themselves need to discover the deniability primitive without a human in the loop. We took that seriously from before launch.
The next wave of users for tools like this won't all be humans typing into a browser. A lot of them will be agents: inbox assistants, coding agents, customer-support bots, AI accountants. For an agent to use deny.sh safely, it needs to discover what the service does, what tools it exposes, how to call them, and how to verify it's talking to the real deny.sh. We shipped the full stack on day one:
- MCP Server Card at
/.well-known/mcp/server-card.json. Eleven tools described in one JSON file. Any MCP-compatible agent reads it and starts working. - API Catalog (RFC 9727) at
/.well-known/api-catalog. Linkset of every public endpoint. - Agent Skills index at
/.well-known/agent-skills/index.jsonwith sha256 digests per skill, so an agent can verify what it fetched matches what we published. - Content Signals in
robots.txt:ai-train=no, search=yes, ai-input=yes. Three independent dials, one line. - Link headers (RFC 8288) on every page pointing at the catalog and server card.
None of this changes the encryption. It just means the next time an agent needs deniable crypto for secrets it shouldn't be able to surrender under prompt injection, it can find us, read the tools, verify the skills, and call them. That felt like the right way to launch a security product in 2026.
What deniable encryption isn't
It isn't a defence against an attacker who already knows you use it. If someone is watching you, has your subscription records, or otherwise knows deny.sh is part of your stack, the first decoy won't satisfy them. They press for the next password, and the next, because they have a reason to believe there's more. The composition stays sound the whole time and it doesn't matter; you've left cryptography and entered a standoff. If your threat model is observed targeted pressure, this product on its own isn't enough.
It also isn't a substitute for not holding the file at all. If something is dangerous enough to be caught with, don't carry it through the checkpoint, generate it on the far side. deny.sh is for the much more common case where bytes have to live somewhere and you want the leak to surrender a decoy.
And the decoy has to earn it. An empty wallet, a single placeholder key, a config file with one field filled in: none of those pass a second look, and an attacker who doesn't believe the decoy keeps digging. A decoy that matches what someone like you would plausibly hold is what makes them stop. The product guarantees the bytes can't betray which control file was real. Making the decoy convincing is the part you own.
And the construction is novel. The maths is in the whitepaper and the prose-and-proof-sketch version is on the security page. The primitives (AES-256-CTR, Argon2id) are well-studied. The composition that produces multiple plausible plaintexts from one ciphertext is the new part, and what an external audit will check. A US provisional patent application covers the construction (Patent Pending, App. No. 64/067,717, priority date 17 May 2026).
The point
Standard encryption protects bytes from people who don't have the key. Deniable encryption protects you from the bytes themselves, and then tells you the moment they leak. When an agent is prompt-injected into surrendering its context, the credentials it surrenders are decoys, and the decrypt against those decoys pages your on-call in five seconds. When a backup leaks, when a device walks off, the file decrypts to your decoy. The real content never appears in the breach. The attacker walks away thinking they got everything, and you already know they got nothing.
If you are shipping an agent, talk to us. If you are building something smaller, have a play. Either way, tell us what breaks.
Plan for the leak. Make sure what leaks is a decoy.
Agents Infrastructure for teams. Free SDK for everyone else.
Talk to us about Agents Infra