Skip to main content
Glama
   █████╗  ██████╗ ███████╗███╗   ██╗████████╗
  ██╔══██╗██╔════╝ ██╔════╝████╗  ██║╚══██╔══╝
  ███████║██║  ███╗█████╗  ██╔██╗ ██║   ██║   
  ██╔══██║██║   ██║██╔══╝  ██║╚██╗██║   ██║   
  ██║  ██║╚██████╔╝███████╗██║ ╚████║   ██║   
  ╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚═╝  ╚═══╝   ╚═╝   
███████╗███████╗ ██████╗██████╗ ███████╗████████╗
██╔════╝██╔════╝██╔════╝██╔══██╗██╔════╝╚══██╔══╝
███████╗█████╗  ██║     ██████╔╝█████╗     ██║   
╚════██║██╔══╝  ██║     ██╔══██╗██╔══╝     ██║   
███████║███████╗╚██████╗██║  ██║███████╗   ██║   
╚══════╝╚══════╝ ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝   

· zero-knowledge · one-time · self-destructing ·

v1.0.0

Cloudflare Workers Zero-knowledge Agent needs just a fetch License

encrypt in the browser · hand your agent a self-destructing link · the server never sees it

▶ agent-secret.xndr.io


⚡ what it does

You need to get an API key into an AI agent. Paste it into the chat and it lives in the transcript, the logs, and the model context — forever. agent-secret fixes the handoff:

┌──────────────────────────────────────────────────────────────────────────┐
│                                                                          │
│   [ YOU ]                    [ agent-secret ]              [ YOUR AGENT ] │
│                                                                          │
│   type secret   ──encrypt──▶  stores only        ──fetch──▶  fetches +   │
│   in browser     in browser   ciphertext + iv     one time   decrypts    │
│                               (never the key)                locally     │
│                                                                          │
│                          🔥 burns on first read                          │
└──────────────────────────────────────────────────────────────────────────┘

The encryption key is generated in your browser and lives only inside the instruction you hand your agent. It never touches the server. So a full database dump — or a subpoena, or a rogue operator reading the source — recovers nothing but ciphertext. That's the whole product.

Related MCP server: @1claw/mcp

✦ the flow

1. You open agent-secret.xndr.io, type the secret + an optional name, hit Encrypt. One click copies a block that's deliberately tiny — one line and one link:

OPENAI_API_KEY — one-time secret (agent-secret). Single GET burns it; then AES-256-GCM
decrypt: response {ct,iv} base64, key = URL #fragment (base64url), ct = ciphertext+16-byte
tag, plaintext = the value.
https://agent-secret.xndr.io/k7f2-9m3q#Xy9…KEY

2. You paste that into your agent's chat.

3. Your agent GETs the link (curl and fetch drop the #fragment, so the server only sees /k7f2-9m3q), decrypts the returned {ct,iv} with the key from the fragment, and writes the value wherever it keeps secrets. The value never went through the model as something you typed, and the link is now dead.

The whole handoff is one link: agent-secret.xndr.io/<code>#<key>. The key rides in the fragment — which browsers, curl, and fetch never transmit — so it reaches your agent but never the server.

🔒 how it stays zero-knowledge

╭──────────────────────────────────────────────────────────────────────────╮
│                                                                          │
│  ◆ CLIENT-SIDE CRYPTO   AES-256-GCM in the browser (WebCrypto). Only     │
│                         ciphertext + a random nonce are ever POSTed.     │
│                                                                          │
│  ◆ KEY NEVER SENT       the 256-bit key is generated in-page and baked   │
│                         into the copy block. The server can't derive,    │
│                         log, or store it — it never arrives.             │
│                                                                          │
│  ◆ SINGLE-USE           the first GET returns the ciphertext and writes  │
│                         a tombstone in the same step. Read #2 → 410.     │
│                                                                          │
│  ◆ SHORT TTL            5 min – 24 h, auto-purged from KV on expiry.     │
│                                                                          │
│  ◆ RATE LIMITED         per-IP fixed window blunts code enumeration.     │
│                                                                          │
│  ◆ NO SERVER SECRETS    the Worker holds no keys of its own. Read the    │
│                         source — nothing there can read a stored secret. │
│                         Verifiable, not a promise.                       │
│                                                                          │
╰──────────────────────────────────────────────────────────────────────────╯

Threat model, honestly. The claim code and the decryption key travel together inside the block you paste. Whoever holds that block can decrypt — exactly once — so treat it like the secret until your agent has claimed it. If an interceptor reads it first, your agent's fetch usually fails (410) — tamper tends to be loud. One caveat: single-use is best-effort, not atomic — Workers KV has no compare-and-set, so a claim racing your agent within KV's short propagation window may not be detected (front the claim with a Durable Object if you need strict once-only). What the server cannot do, by construction, is read your secret — at rest or in flight.

Unfurl-safe. Pasting the link into Telegram, Slack, Discord, etc. is fine — their preview crawlers are detected and served a no-op, so they never burn the secret. (They couldn't read it anyway: crawlers don't send the #fragment.)

🤖 for the agent

No install, no MCP, no SDK. Given the link https://agent-secret.xndr.io/<code>#<key>, an agent needs one HTTP GET and a standard AES-256-GCM decrypt:

GET https://agent-secret.xndr.io/<code>        # send WITHOUT the #fragment (curl/fetch already drop it)
  → 200 {"ct":"<base64>","iv":"<base64>"}   (and the secret is now burned)
  → 410 already_claimed | expired
  → 404 not found

decrypt:  AES-256-GCM
  key    = base64url-decode(<the #fragment>)   # 32 bytes
  nonce  = base64-decode(iv)                    # 12 bytes
  tag    = last 16 bytes of base64-decode(ct)
  data   = base64-decode(ct) minus the tag
  plain  = the secret value (UTF-8)

Many libraries (WebCrypto, Python cryptography) take ct with the tag appended — pass base64-decode(ct) whole and skip the manual split. OpenSSL/Node-style APIs want the tag separated, as shown.

🛰 api

Method

Path

Purpose

GET

/

The share form (all crypto runs here).

POST

/

Create. Body { ct, iv, ttl? } (base64 ciphertext + nonce). → { code, expiresAt, ttl }

GET

/:code

Claim + burn.{ ct, iv } once, then 410. (Preview crawlers get a no-op.)

GET

/:code/meta

Lifecycle only — { exists, claimed?, expiresAt? }. Never ciphertext.

DELETE

/:code

Destroy immediately.

🚀 self-host

It's a single Cloudflare Worker + one KV namespace. No secrets to configure — the server is stateless about keys by design.

$ git clone https://github.com/mrcsXndr/agent-secret && cd agent-secret
$ npm install

# In wrangler.toml: set your own account_id, and replace (or remove) the
# [[routes]] block with your domain — the shipped values are XNDR's.
$ npx wrangler kv namespace create SECRETS      # paste the id into wrangler.toml
$ npx wrangler deploy

$ npm run dev                                    # local: http://localhost:8787
$ npm test                                       # vitest — incl. full E2E round-trip

RATE_LIMIT_PER_MIN (default 30) is the only knob, in wrangler.toml.

🧱 stack

Cloudflare Workers · Hono · Workers KV · WebCrypto (AES-256-GCM) · TypeScript · Vitest — no runtime dependencies beyond Hono.

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mrcsXndr/agent-secret'

If you have feedback or need assistance with the MCP directory API, please join our Discord server