Skip to content
QC Failed
GitHub ↗

Featured workCase file

Developer tool / one-time secret bridge

shh

open source

A family errand needed a gift-certificate link pulled out of a chat transcript, and the obvious answers — paste the secret into the chat, or trust redaction to clean it up later — were both wrong. shh is the one-time bridge that grew out of that moment.

The task sounded small: pull the gift-certificate link for a planned outing out of a conversation and hand it to the agent. The problem was structural. The link was bearer-like credential material, and the natural ways to move it — pasting it into the chat or letting transcript redaction tidy it up afterward — put plaintext where it did not need to exist in the first place.

shh is the deliberate alternative: an open-source, MIT-licensed, self-hostable one-time secret bridge. It moves values between a human and an AI agent in both directions while keeping plaintext out of chat and model context. The hosted instance at shh.qcfailed.com is a best-effort public demo with no account or SLA; serious installations can self-host.

  • Two directions: Human → Agent and Agent → Human
  • Browser encrypts before the relay ever sees plaintext
  • One-time claims and short-lived drops
  • Open source and self-hostable

Fig. 1Diagram

Synthetic workflow illustration — no secret or handoff link is shown

At a glance

Category
Developer tool / one-time secret bridge
Status
open source
Source
public
Live
shh.qcfailed.com
Stack
Python, JavaScript, PyNaCl, libsodium, Playwright, Docker
Proof points
  • two directions: human → agent and agent → human
  • browser-side encryption before upload
  • opaque ciphertext relay with one-time claims
  • public agent onboarding via /agent.md and /llms.txt
  • pytest and real-browser verification

01 / Story

Twenty minutes of cow cuddling

The family had booked a farm tour followed by exactly twenty minutes of cow cuddling. Retrieving the gift-certificate link for that outing exposed the missing half of the product: the agent needed a value from a human, and every available mechanism put that value somewhere it should not go.

The certificate itself never appears here — no value, URL, or vendor detail. What mattered was the pattern: a human-held credential needed to cross into an agent workflow, and the only good answer was a delivery mechanism designed for the boundary, not a redaction feature bolted on afterward.

02 / Story

The original boundary: keep credentials out of chat

The first direction, Human → Agent, exists because credentials should not be pasted into chat or model context. Transcript redaction can scrub a known secret after the fact, but it cannot un-leak a value that was already sent, and it cannot know about values it was never told to look for.

The original flow made the receiving side explicit: the agent creates a receiver keypair and a public delivery link, a person opens the complete link and encrypts in the browser, and the relay stores only opaque ciphertext. The receiver decrypts locally and writes one declared .env value — a fixed target, not an open write primitive.

The receiver private key never enters the delivery link, a request, or normal output. Redaction remains a useful hygiene layer; it is just not the security mechanism.

03 / Story

The reverse direction was the product lesson

The second direction, Agent → Human, came from the same incident viewed from the other side. The agent had a value — the gift-certificate link — that needed to reach a human without passing through chat or model context. Posting plaintext was unacceptable, and a reusable secret would linger.

The reverse flow uses a short-lived one-time reveal instead: the agent reads a value from stdin, encrypts it with a fresh symmetric key, and uploads ciphertext. The agent prints a single-use reveal link whose fragment carries the drop id and the key, the person opens it in the browser, and a one-time claim deletes the ciphertext from the relay.

That is a product need, not a scanner exploit: hand a secret back out of an agent workflow with the same boundary discipline the inbound direction already had.

04 / Flow

Human → Agent

  1. STEP 01

    Declared receiver

    Agent creates a receiver keypair and a public delivery link; the receiver private key never enters the link.

  2. STEP 02

    Browser encrypts

    Person opens the complete link and encrypts in the browser — plaintext exists only client-side at this point.

  3. STEP 03

    Opaque ciphertext relay

    Relay stores only ciphertext plus lifecycle metadata; a reveal URL is a live bearer capability until claimed.

  4. STEP 04

    One-time claim

    Receiver decrypts locally and writes one declared .env value; the drop is claimed once.

Fails closed

  • Plaintext exists only in the person's browser and the receiver's local decrypt step — never in the delivery link, a request, or normal output
  • Browser fragments are not sent in ordinary HTTP requests; capability material stays out of server-visible paths where applicable
The Human → Agent flow: declared receiver, browser-side encryption, opaque relay storage, one-time claim.

05 / Flow

Agent → Human

  1. STEP 01

    Agent encrypts

    Agent reads a value from stdin and encrypts with a fresh symmetric key — no literal secret in argv or chat.

  2. STEP 02

    Opaque ciphertext relay

    Agent uploads ciphertext; relay stores it once for the drop's short lifetime.

  3. STEP 03

    One-time reveal

    Person opens the reveal link in the browser and claims it once; claiming deletes the ciphertext from the relay.

  4. STEP 04

    Copy / hide

    Browser decrypts locally, removes the capability fragment, and shows the value until the user copies or hides it.

Fails closed

  • The reveal link is a live bearer capability until claimed — anyone who opens it first can claim the secret
  • Fragment removal, the copy/hide lifecycle, and the bounded fallback timer are screen hygiene, not cryptographic containment
The Agent → Human flow: agent-side encryption, opaque relay storage, one-time browser reveal, copy/hide lifecycle.

06 / Decisions

Selected decisions

Current implementation facts; the source repository is the authority for details:

  1. Capability material stays in URL fragments where applicable

    Drop ids and keys live in fragments rather than ordinary request paths, so they are not sent in ordinary HTTP requests.

  2. One-time claim and short TTL

    A drop can be claimed once, then the ciphertext is deleted; short time-to-live bounds how long a capability lingers.

  3. Explicit Reveal / Copy / Hide lifecycle

    The reveal step removes the capability fragment after decryption, and copy/hide gives the person deliberate control of the plaintext on screen.

  4. Bounded fallback timer as screen hygiene

    A 120-second fallback clears the revealed value — privacy hygiene for shared screens, not a containment guarantee.

  5. Payload, storage, and rate boundaries

    Limits control abuse and lifecycle; they are not identity or access control.

  6. Strict CSP and no-store where implemented

    The served page and relay follow the documented CSP and caching posture; verify the current source for exact headers.

07 / Constraints

What shh is not

Documented boundaries from the security model:

  • Not a vault, identity provider, credential broker, or general file-write primitive
  • The same-origin operator serves the JavaScript and could replace it to capture future plaintext — not hostile-operator-resistant
  • A fully privileged hostile agent is outside the containment boundary
  • Reveal links are capabilities, not access control; keep them private and claim promptly
  • Short TTLs and one-time claims limit abuse; they are not authentication

08 / Story

Public onboarding for humans and agents

The bare domain is useful once a link exists, but it originally made little sense without a generated link. Public onboarding closes that gap: a landing flow for humans plus machine-readable discovery for agents.

Agents are pointed at https://shh.qcfailed.com/agent.md for the supported handoff helpers, and llms.txt provides a short discovery record. Self-hosted deployments derive the same agent-discovery URL from their active origin.

09 / Story

Dogfooding: the tool carried its own onboarding credential

shh carried the GitHub credential needed to push and open its own public onboarding PR. The credential, capability URL, file contents, and private operational identity are not repeated here — the result is what matters: the tool moved real authentication material across the boundary it was designed for, without putting it in chat or model context.

A delivery-UX lesson came out of the same period: a clickable-link label mattered enough in the Discord channel that the landing copy was refined for how links actually render. Delivery UX is part of a security workflow, not decoration.

10 / Story

How it is verified

The repository runs unit and handoff coverage with synthetic test data, plus real-browser Playwright journeys exercised against an external relay. A Docker container handoff is part of CI, and results were confirmed by reading the CI logs directly rather than trusting a status badge alone.

The curated visual on this page is a synthetic workflow illustration, not a screenshot of a live handoff. No real drop, key, or capability material is shown anywhere in this case file.

One review correction is worth recording: syntax alone did not prove a decoded receiver key had the required 32-byte length. Review added decoded-length validation and a regression test before merge — the lesson is verification discipline, not spectacle.

11 / Story

Honest threat boundaries

The same-origin server supplies the JavaScript; a compromised or malicious operator could replace future client code and capture plaintext before encryption. Self-hosting is the answer when that trust boundary matters.

A fully privileged hostile agent is outside the containment boundary. Reveal links are live capabilities until claimed, and hide/timer behavior protects screen privacy — it is not cryptographic containment. There is no zero-trust, vault, or unhackable claim here.

12 / Evidence

Evidence

The public sources behind this case file:

13 / Status

Current status and next direction

shh is live at https://shh.qcfailed.com, open source, and self-hostable today. The hosted instance is a best-effort public demo with no account, SLA, or identity guarantee.

Related work: the Request Minimizer case file covers a sibling credential-exposure experiment. No roadmap is invented here; the public agent guide and the repository are the current sources of truth.

Next direction

  • Ground any later direction in current repository issues before proposing it; nothing in this case file invents one.