Deniability infrastructure
for AI agents.
Every secret leaks eventually. Your agent will be prompt-injected; make sure what leaks is a decoy.
- Per-tenant isolation
- RFC 3161 hash-chained audit
- Open source, free forever
Decoy. Tripwire. Page. Rotate.
Decoy leaks
An injected agent surrenders its context. What it surrenders is a shape-correct, validator-gated fake.
never the real keyTripwire fires
Every decoy is hashed and armed. The instant those bytes hit a decrypt endpoint, a critical event fires.
before the response returnsYou're paged
The event fans out to Datadog, PagerDuty, or Slack. On-call sees it in about 5 seconds.
~5s to on-callFires your rotation hook
On programmatically-managed secrets, your rotation hook fires in the same instant. The real key is revoked before anyone reads the alert.
containment, automaticAWS KMS, HashiCorp Vault
Guard your secrets from outsiders.
deny.sh
Guards them from your own agent. It sits on top of the secrets manager you already run.
The leak-survivable layer under your secrets.
Behind every consumer-facing AI agent sits a vault of OAuth tokens, API keys, and customer credentials. One well-aimed prompt injection and the agent reads its own context aloud, and the standard secret managers have no answer for an authenticated agent that's been talked into leaking.
deny.sh sits on top of the secrets manager you already run and changes what's there to leak: the injectable side of your agent only ever reaches a believable decoy, the real key resolves in your trusted runtime, and every touch of a decoy is a tripwire. Three things it gives you:
The agent only sees a decoy
Each tenant gets a unique decoy bundle: OpenAI keys, AWS credentials, Stripe secrets, JWTs, recovery phrases, Postgres URIs. Shape-correct, validator-gated, structurally indistinguishable. The real keys live behind a control file the agent was never handed.
One breach, one tenant
Per-tenant key derivation, per-tenant audit log, per-tenant rate limits. A compromised agent leaks one customer's decoys, not the whole fleet. The blast radius matches the threat model.
Hash-chained, RFC 3161 timestamped
Every encrypt, decrypt, and key access lands in a tamper-evident chain with independent TSA receipts. After an incident you prove what actually happened. Your regulator verifies the receipts without trusting us.
Decoy bundles double as silent tripwires: arm a bundle once, and the loop above runs the moment an attacker touches those bytes. See the loop.
The same attack, with and without it, plays out below.
Follow the attack down.
The decoy shown is real engine output of the same class the SDK generates, drawn from the same validator-gated bundle. Generate your own live at /encrypt.
The questions every good engineer asks.
Not the procurement questions, the architecture ones. If you're the dev who has to wire this in, these are the things you want answered before you trust it. Straight answers, no hand-waving.
Does my employee (or my agent) still get the real key when they're legitimately working?
Yes. Nobody is handed a fake key to work with. The real credential is resolved inside your tool boundary, the deterministic code that actually executes a call, and that path uses the real value to do the real work. What never holds the real value is the model's context, the part that reads emails, documents and user input and can be prompt-injected. Same credential, two doors: the legitimate runtime door opens the truth, the injectable model door only ever reaches a decoy.
How do you tell a prompt injection apart from a real user request?
We don't, and that's the point. deny.sh does not run a runtime classifier asking "is this prompt malicious?" That detection is unreliable and you'd never trust your secrets to it. The protection is architectural, not a yes/no judgement: the real secret simply never enters the surface that can be injected. There's nothing to decide per-request, because the only thing reachable from the injectable context is a decoy, by construction.
So something decides which password resolves. Where does that actually live?
The selector lives in the control file you hold, never in the agent. The real password sits in your runtime / orchestration layer (the privileged code that runs a tool call or a DB query) and resolves the true plaintext there. The model only ever has a reference and the decoy control file. So deny_decrypt called from the legitimate path returns the real value; the same call reachable from an injected context returns a decoy, and the decrypt against it is logged. The agent has no theory of mind, it can't suspect a second plaintext that isn't in its context.
I already quarantine secrets behind a proxy so the agent never sees them. Why do I need this?
If you've genuinely quarantined the key and the agent can never reach the store, that proxy pattern is the correct baseline, and deny.sh sits underneath it, not instead of it. The delta is what happens when quarantine fails open (an over-scoped tool, a path traversal, a misconfig, a future capability). Quarantine is a prevention boundary; prevention boundaries fail open, and the day it fails the live key is in context. With the credential stored as a deny ciphertext, that same breach yields a believable decoy instead, and the decrypt pages your on-call. It also does the thing access-control structurally can't: make the disclosed value deniable under coercion. Quarantine reduces the odds of a leak; deny.sh makes the leak survivable. See the full architecture →
Won't the attacker just test the leaked key against the live API and learn it's fake?
That test is the tripwire. The moment they try to use the decoy, two things have already happened: the decrypt that produced it paged your on-call, and on programmatically-managed secrets your rotation hook revoked the real key. So the attacker's own verification step is your earliest breach signal and your containment trigger in one. The decoy doesn't have to survive scrutiny forever; it only has to be believable for the seconds it takes them to reach for it. By the time it fails their test, the real credential is already dead and you already know. The breach you were dreading becomes the alert you needed.
Isn't this just Canarytokens or honeytokens?
Honeytokens are bait placed next to the real key: the live credential is still sitting there reachable, and the canary only tells you after something tripped on the decoy beside it. deny.sh inverts that. The real key is unreachable from the injectable surface in the first place (architectural, not bait), the value the attacker does get is a cryptographically indistinguishable decoy of the same credential (not an obviously-different tripwire token), and the alert fires its own rotation so containment is automatic. Honeytokens are detection bolted beside the asset; deny.sh makes the asset itself leak-survivable. You can absolutely run both.
Want to argue the threat model? It's all written down, honestly, at /threat-model, including what deny.sh doesn't defend against.
Generate it. Arm it. Get paged and rotate the moment it's touched.
A decoy isn't a static string you write once. It's generated to be unfingerprintable, armed as a tripwire, turned into your earliest breach signal, and on programmatically-managed secrets it triggers the real key's rotation the instant it's read. Four phases, one primitive. On structured types, Honey Mode now does the first two in a single call.
Decoys you couldn't write yourself.
The realism engine generates shape-correct, validator-passing decoys across 69 credential types: API keys, crypto wallets, healthcare records, bank and securities identifiers, government IDs. Declare the type, get a fake that passes the same checks the real one would. Different bytes every time.
sk-proj-1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t…
Every specimen is real engine output, validator-gated. Generate your own at /encrypt, or read the architecture.
Skip the two-step. Let the decoy generate and arm itself.
Generating a decoy and arming it as a tripwire are two operations above. Honey Mode collapses them into one. Pass a structured type to encryptHoney(secret, p1, p2, type) (or --honey --honey-type on the CLI) and the wrong password no longer returns the noise of a failed decrypt: it returns a freshly generated, validator-gated, shape-correct fake of that exact type. The decoy is auto-generated at decrypt time and its fingerprint is pre-armed, so the tripwire fires the moment a wrong-password decrypt produces that fake. Different fake bytes every time, deterministic per record, no decoy pool to maintain.
Structured types only. Honey Mode is eligible across 63 of the 69 credential types and refuses the unstructured catch-alls plus four JSON/URI types: data with no fixed shape can't be faked convincingly, so we never pretend it can. Live in every reference SDK (npm, PyPI, crates, Go). Honey Mode docs.
Turn each decoy into a silent tripwire.
A realistic decoy protects the real data. Arming it tells you when someone reaches for it. Hash a fake credential locally, register the 32-byte fingerprint with us, and the decoy becomes a tripwire. Only the hash crosses the network; the decoy bytes stay yours. Two kinds, matched at different points in the decrypt.
Fires before the attacker reads anything.
You hash a decoy controlData file (the deniable-encryption fingerprint). We check it before the decrypt runs. Wrong password? Still fires. Right password? Still fires. The match happens on the hash alone, so the alert is independent of whether the attacker has the right key.
Drop the decoy controlData in a README, an internal wiki, an over-privileged S3 prefix, the customer-support inbox. The first time anyone runs /api/decrypt against it, you're paged.
Fires the moment the bytes are recovered.
You hash a decoy plaintext (a fake API key, a fake seed phrase). We check it after a successful decrypt against the recovered plaintext. If the attacker has both passwords, decrypts the ciphertext, and the result hashes to a fingerprint you armed: you're paged inside the 5-second envelope.
Pair it with the realism engine. Generate a sample agent bundle, click Arm This Bundle on /agents, register every fake credential as a plaintext tripwire in one round-trip. Zero infra to wire up.
# hash the decoy plaintext locally; only the hash crosses the network
HASH=$(printf '%s' "$DECOY_VALUE" | sha256sum | cut -d' ' -f1)
curl -X POST https://deny.sh/v1/decoy-tripwires \
-H "Authorization: Bearer $DENY_CONSUMER_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tripwire_hash\":\"$HASH\",\"tripwire_kind\":\"plaintext\",\"label\":\"stripe-prod decoy\"}"
The leak becomes your earliest warning.
The moment an armed decoy is touched at any decrypt endpoint in your tenant, a critical event lands in the audit chain and pages your on-call. Then you watch the intruder show up, live, in your dashboard. The breach you were dreading becomes the alert you needed.
Tripwires start on Pro ($199/mo, 10k tripwire cap); bulk-arm at customer-DB scale on Agents Infrastructure ($999/mo, 1M tripwire cap). Full spec on the Agents Infrastructure pillar; bulk recipe at /agents/arm-at-scale; dashboard at /dashboard/decoy-alerts.
Who this is built for.
Same wire format, same threat model, same construction. Three ways teams put it to work.
-
01 / platform operator
Running an AI agent platform.
Serving paying customers who store secrets in agents that get prompt-injected. Per-tenant key isolation, per-tenant audit log, MCP server, named SLA. Agents Infrastructure tier, $999/mo. Agent docs.
-
02 / builder
Shipping it inside your product.
Adding deniable storage to something you're building. SDK in TypeScript, Rust, Go, and Python. Apache 2.0, zero copyleft, drop-in. Pick a language,
npm install deny-sh, ship. -
03 / enterprise
On the balance sheet.
Regulated organisation, custody platform, or security product where deniability needs to land in your audit trail. Self-host or private deployment, bring your own KMS, structured audit events for SOC 2 / ISO 27001. From $25K/year.
Four trust anchors. All published. All checkable.
AES-256-CTR, Argon2id, and XOR composition. Standard primitives, open construction, no magic. A deniability product gets held to a higher bar, so we publish all four layers.
What we defend against.
What we partially defend against. What we do not defend against at all. Plain English, no equivocation.
Read /threat-model →Five-step algorithm.
Named primitives at every step (SHA-256, Argon2id, AES-256-CTR, XOR). Deniability proof sketch. KAT byte-compat across four SDKs.
Read /security →48h acknowledgement.
Coordinated disclosure. GPG key on keys.openpgp.org. RFC 9116 signed security.txt. Safe harbor for good-faith research.
Signed everything.
Signed git tags. npm / crates / PyPI / Go-module integrity. SRI on every served asset, with a machine-readable manifest at /.well-known/integrity.json.
UK operator. Cyber Essentials Certified (IASME, May 2026). Trust Center · Controls map · Status · How to verify deny.sh.
Proxy quarantine vs. deny.sh.
They're not alternatives, they're layers. Quarantine lowers the probability of a leak. deny.sh lowers the impact when one happens anyway, and adds deniability no access-control can give you.
| Proxy quarantine alone | + deny.sh underneath | |
|---|---|---|
| Agent never reaches the key | Yes, while the boundary holds | Yes, same baseline, kept in place |
| When the boundary fails (misconfig, over-scoped tool, traversal, future bug) | Live key is in context. Real leak. | Fails safe: a shape-correct decoy leaks, not the live key |
| You find out a leak happened | Weeks later, in the incident report | In seconds: decrypt against the decoy pages on-call |
| Coerced, compelled, or insider disclosure of the value | No answer. The key is just the key. | Disclosed value is a cryptographic decoy, indistinguishable from the real one |
| What it controls | Access (probability of a leak) | Impact + deniability (survivability of a leak) |
If you can perfectly quarantine, do that as well. deny.sh is for when you can't, and for when you need the leaked value itself to be deniable rather than just gated.
Six questions your security team will ask.
Every encryption tool sells the maths. The conversation a procurement team actually has is about audit evidence, billing safety, key control, integration time, incident response, and verifiable posture. We have an answer that's live for each one.
01 · live
Prove what happened, without trusting us.
Tamper-evident hash chain over every operation. RFC 3161 timestamps from an independent TSA. Your regulator verifies the receipts. We cannot fake them after the fact.
02 · live
Know when a decoy gets touched.
Register decoy fingerprints as tripwires. The first matching decrypt attempt writes a critical audit event and fans out to your incident channel.
03 · live
No surprise bills, no silently burned keys.
Per-tier daily caps. Email alerts at 80, 95, and 100 percent. Quota events join the audit chain. You see the spend before it lands.
04 · live
Hold the keys in your own AWS account.
Server-stored ciphertext wrapped under your AWS KMS CMK. Revoke us and your data goes dark. We literally cannot decrypt it.
05 · live
Wire into your stack in an afternoon.
Copy-paste adapters for nine agent frameworks (Vercel AI SDK, LangChain, OpenAI Agents SDK, OpenAI Responses, CrewAI, LlamaIndex, AutoGen, Pydantic AI, n8n) plus native MCP. SAML SSO and signed webhooks for Datadog, PagerDuty, Slack. Arm decoys as tripwires from the dashboard.
06 · live
Procurement-ready evidence on day one.
Cyber Essentials certified today. Public self-attested controls mapping against SOC 2 and ISO 27001; independent SOC 2 Type II examination and a cryptographic audit on the post-launch roadmap. Live status page, honest roadmap blog, every claim links to verifiable evidence.
Every answer above is live in production. See the Trust Center or the controls map for the full evidence pack.
Built for teams that protect data at rest.
Custody platforms, exchanges, and security products. The same primitive that protects an individual key protects an institution's vault.
Apache 2.0 SDK, commercial app layer
Embed the SDK in any product, proprietary or open, with no copyleft surface. Application-layer (vault, dispatcher, dashboard) is dual-licensed AGPL or commercial.
On-prem or VPC, full audit trail
Run deny.sh inside your own infrastructure. Customer-controlled BYOK encryption under your AWS KMS CMK. Tamper-evident audit chain with RFC 3161 signed receipts. SAML SSO for workforce identity. Every claim mapped to SOC 2 + ISO 27001 in the public controls map, and specified in whitepaper §6.
Dedicated SLA, named escalation
99.9% uptime SLA, 30-min P1 response, named security and engineering escalation paths. UK / EU / US business-hours coverage with on-call escalation.
Agents Infrastructure at the top. Self-serve below.
One ladder. Engineering teams shipping AI agents at the top. Individual developers and consumer tools underneath. CLI and browser tools free forever.
For engineering teams shipping AI agents with secrets in context.
The hosted runtime that puts decoys in front of every prompt-injected leak. Per-tenant key isolation, scoped audit log, signed webhooks, BYOK under your AWS KMS CMK. Same construction as the free SDK; multi-tenant operational discipline on top.
- 1M API calls / month
- Per-tenant key isolation
- Per-tenant audit log
- Live decoy feed + cross-network threat intel
- RFC 3161 timestamps
- SAML SSO, signed webhooks
- BYOK (AWS KMS)
- MCP server (7 hosted tools)
- Named SLA + escalation
Self-serve API tiers
- 500 API calls/month
- Full encrypt, decrypt, deny
- Realism engine: 10 decoys/day
- Vault storage (25 items)
- Community support
- 10,000 API calls/month
- Full encrypt, decrypt, deny
- Realism engine: 100 decoys/day
- Vault storage (1,000 items)
- Audit log + email support
- 100,000 API calls/month
- Full encrypt, decrypt, deny
- Realism engine: 1,000 decoys/day
- Live decoy feed + cross-network threat intel
- Vault storage (10,000 items)
- Priority support + SLA
Between Pro and Agents Infrastructure.
250K API calls, 25K decoys/day, 365-day audit retention. Self-serve via Stripe, email support. No hands-on onboarding, no named SLA. For one or two agents in production before you need the $999/mo tier.
Underneath the agent runtime: a general deniability primitive.
The same construction that keeps a decoy in front of a prompt-injected agent protects any bytes at rest, with no account and no infrastructure. Standard encryption gives an attacker one answer: right key, game over. deny.sh gives the same ciphertext two plausible plaintexts, and no forensic tool can tell which is real.
Two passwords, one ciphertext, two control files. One opens the real plaintext, the other a believable decoy. The passwords never change; swapping the control file swaps the truth. Works just as well for an agent's secret store as for a single file in your browser, and it's the at-rest and under-coercion layer beneath everything above.
# ~3 KB minified · one runtime dep (hash-wasm) · types included
Five surfaces, one wire format, one threat model. Encrypt in the browser, decrypt from the CLI. Encrypt from an agent via MCP, decrypt from your phone. The bytes don't care which surface produced them.
Prefer apps to an SDK? The deny.sh toolkit: Encrypt Anything, Vault, browser helpers → · Shipping into an agent framework? Browse the integrations →
Every tool below encrypts well. Only one can lie about what's encrypted.
| deny.sh | VeraCrypt | PGP | BitLocker | |
|---|---|---|---|---|
| Plausible deniability | ✓ | Partial | ✗ | ✗ |
| Cryptographic deniability | ✓ | ✗ | ✗ | ✗ |
| Multiple decoys from one file | ✓ | ✗ | ✗ | ✗ |
| AI-generated decoys (shape-correct, validator-gated) | ✓ | ✗ | ✗ | ✗ |
| Decoy tripwires (alerts on decoy decrypt) | ✓ | ✗ | ✗ | ✗ |
| No hidden partition needed | ✓ | ✗ | ✓ | ✓ |
| Works on single files | ✓ | Volumes | ✓ | Drives |
| API / SDK | ✓ | ✗ | CLI | ✗ |
| Tamper-evident audit trail (RFC 3161) | ✓ | ✗ | ✗ | ✗ |
| Decoy tripwires + incident webhooks | ✓ | ✗ | ✗ | ✗ |
| Customer-controlled BYOK (AWS KMS) | ✓ | ✗ | ✗ | ✗ |
Hidden volumes are detectable by disk usage analysis. deny.sh has no volumes, no partitions, no structural tell. Full comparison.
Plan for the agent leak, not after it.
Engineering team shipping AI agents? Get hands-on onboarding for the Agents Infrastructure plan. Building something smaller? Try the free SDK, no account needed.
What leaks is a decoy.