Stop sending passwords in Teams.
Cyphera SecureSend is one-time secret handoff for controlled environments. The sender types a secret, sets a password and an expiry, and gets a link. The recipient opens the link, enters the password, reads the message once, and it is gone. Encrypted in the browser, held in memory, one binary, no database. Runs in your environment: Cyphera never receives your secrets.
The problem
Somebody has to give a colleague the temporary password, the API key, the initial admin credential, the service-account secret. It goes into chat or email, and from that moment it lives in searchable retention for years.
TODAY Alice → Teams: "temp admin pw: Dfj$938..." Stored in Teams retention. Forever. SECURESEND Alice → Bob: https://send.acme.example/m/… Password sent separately. Bob opens it once. It's gone. Audit: Alice → Bob, 10:32, read once.
A vault answers where a secret should live. SecureSend answers the moment before that: how to get it to one person, once, without leaving a copy behind. It is not a password manager and not a vault. It handles the handoff, and then the handoff artifact disappears.
It runs where you run it: your identity, your logs, your infrastructure. There is no hosted service to send your secrets to, and Cyphera never sees them.
How it works
Everything cryptographic happens in the recipient's and sender's browsers using the Web Crypto API. The server never receives the plaintext, the password, or the encryption key.
SENDER'S BROWSER
password + random link secret
→ PBKDF2 → HKDF → K_enc, K_proof
ciphertext = AES-256-GCM(K_enc, plaintext)
send: ciphertext, SHA-256(K_proof) ──► SERVER holds them in memory
receive: id, revoke token ◄── and returns an id
link = /m/<id>#<link secret…> (the part after # never leaves the browser)
RECIPIENT'S BROWSER
open link, enter password → derive K_proof
send: proof ──► SERVER verifies hash + removes
receive: ciphertext (exactly once) ◄── in one atomic step
decrypt, show once
Two details do most of the work:
- The link carries a secret in its fragment. Browsers never send the part after
#to a server, so it is absent from every access log and every proxy. That secret is mixed into the key derivation, so ciphertext taken from the server cannot be attacked without the link, and a captured link is useless without the password. - The recipient proves the password before anything is released. The browser derives a second value from the password and the link secret and sends that. The server compares its hash and removes the message in the same atomic step. A typo does not destroy the message, and someone holding only the link cannot burn it or take the ciphertext away to guess the password offline.
Delivery is strict. Once the server has handed a message to one caller it no longer exists. Two people opening the same link at the same moment get one message and one "unavailable". Every failure looks the same, so nothing reveals whether a message exists.
Features
- Browser-side AES-256-GCM with PBKDF2 and HKDF key derivation; Web Crypto only, no cryptography libraries shipped to the browser
- Ephemeral by design: messages live in bounded process memory and vanish on restart
- Exactly-once retrieval through an atomic verify-and-remove step
- Password proof before release; configurable number of wrong attempts before the message is destroyed
- Sender revocation before retrieval
- Configurable expiry choices and maximum message size
- Uniform responses for every failure; no secret ever in a URL path, log line, or audit event
- Structured audit events (sender, recipient, lifecycle, outcome) as JSON lines, ready for a SIEM
- Prometheus metrics, liveness and readiness probes, graceful shutdown, optional in-process TLS, proxy-aware client addressing
- Strict Content Security Policy with no inline script or style, no third-party origins, no analytics
- Branding from configuration: name, logo, favicon, colors, footer, support link
- Material 3 inspired interface that feels like a small native tool, not a dashboard
- Rust server, TypeScript interface compiled into the binary; runs as a single process with no database
Quick start
# Run it docker run --rm -p 8080:8080 ghcr.io/cyphera-labs/cyphera-secure-send:latest # Or the binary ./cyphera-secure-send serve # Open http://localhost:8080
Make it yours
An enterprise deployment should look like the enterprise's own tool. Branding is configuration, not a rebuild.
branding:
company_name: Acme
product_name: SecureSend
tagline: Share credentials with colleagues, once.
logo_path: /config/logo.svg
support_url: https://help.acme.example/securesend
footer_text: For authorized Acme personnel only.
colors:
primary: "#0057b8"
secondary: "#00a9ce"
Every key is also an environment variable, for container platforms:
CYPHERA_SECURESEND__BRANDING__COMPANY_NAME=Acme CYPHERA_SECURESEND__BRANDING__COLORS__PRIMARY=#0057b8 CYPHERA_SECURESEND__BRANDING__LOGO_PATH=/config/logo.svg
Configuration
It starts with nothing but defaults. A YAML file and environment variables layer on top.
messages: ttl_options_seconds: [300, 900, 3600, 28800, 86400] default_ttl_seconds: 3600 max_plaintext_bytes: 65536 memory_budget_bytes: 268435456 max_failed_proofs: 5 rate_limits: create_per_minute: 10 consume_per_minute: 30 audit: sink: stdout include_client_ip: false
Built for controlled environments
Public, anonymous link-sharing services have a history of being abused to distribute malware and phishing content. SecureSend is meant to run inside an organization, for that organization. Text only, small messages, attributable senders and recipients, and an audit trail of every lifecycle event.
What a security review gets
- A written security model with numbered invariants, each enforced by a test, and a threat model that states its limits plainly
- Signed binaries and a signed multi-architecture container image on every release
- CycloneDX and SPDX software bills of materials and SLSA build provenance attached to every release
- Container runs a single binary as a non-root user with no shell, on a digest-pinned minimal base, and supports a read-only filesystem with all capabilities dropped
- Continuous static analysis, dependency auditing, secret scanning, and OpenSSF Scorecard
- Air-gap capable: no runtime network dependencies of its own
Running it for an organization
Everything in the repository is free to run, forever, under Apache-2.0. If you are rolling it out for an organization and want a support agreement, help with deployment and hardening, or a hand with the security questionnaire, get in touch.
Status
Cyphera SecureSend is alpha software. The core protocol and the one-time semantics are complete and tested; the API and configuration keys may still change before 1.0. It has not been externally audited. See the security policy and the security model, which states what it does not protect against.
Standards & references
- NIST SP 800-38D — Galois/Counter Mode (AES-GCM)
- NIST SP 800-132 — Password-based key derivation (PBKDF2)
- RFC 5869 — HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
- Web Cryptography API — W3C
- RFC 3986 §3.5 — why the URL fragment never reaches the server