crypt.fyi - A zero-knowledge, end-to-end encrypted secret sharing platform that enables secure and private transmission of sensitive data.
- π End-to-end encryption using ML-KEM post-quantum cryptography
- π‘οΈ Strict Content Security Policy (CSP) to prevent XSS attacks and unauthorized resource loading
- π‘οΈ Strict rate limits to mitigate brute-force attacks
- π€« Zero-knowledge architecture - server never sees unencrypted data or decryption keys
- π₯ Burn after reading w/ provisions to prevent erroneous burns from bots or url introspection
- π₯ Burn after
nread failures - β° Automatic expiration (Time-To-Live)
- ποΈ Password protection
- π File sharing support w/ drag and drop
- πͺ Webhook notifications for read success, read failure, and burn events
- π IP/CIDR allow-listing
- π’ Read count limits
- π± QR code generation
- β¨οΈ CLI for interacting with the API
- π§© Chrome Extension
- π³ Docker images for the api server and web client
- π Internationalization support for multiple languages
- Currently supported: View supported languages
- Contributions welcome for new translations!
- Encryption key is generated on the client
- Password is optionally provided
- Encryption key and password are used to encrypt the secret
- Encryption key and password are hashed and stored along with the encrypted secret for verification on retrieval - the raw key and password are never stored or transmitted on/to the server
- The unique URL containing the decryption key is generated on the client
- Share the URL with your recipient and separately the password if specified
- When accessed, only when the decryption key and password match via server-side verification of the hashes, the encrypted secret is shared and decrypted in the recipient's browser
- Optionally, the secret is automatically destroyed after being read in an atomic read & delete operation guaranteeing only one person can access the secret
- If retrieval doesn't happen within the TTL, the secret is automatically destroyed
API_URL=https://{your-domain-here} ENCRYPTION_KEY=$(openssl rand -base64 32) docker compose up --buildENCRYPTION_KEY encrypts IP restrictions and webhook URLs at rest in Redis. Keep it stable across restarts (e.g. in a .env file next to docker-compose.yaml); changing it makes existing secrets with those options unreadable.
API_URL is read when the web container starts, so changing it only needs a restart (docker compose up -d), not a rebuild. It must be a plain http(s)://host[:port][/path] URL; the container refuses to start otherwise.
A prebuilt API server image (linux/amd64, linux/arm64) is published to GHCR on every release:
docker pull ghcr.io/osbytes/crypt.fyi-server:latestIt runs with NODE_ENV=production and requires REDIS_URL and ENCRYPTION_KEY.
The web client image is not published to GHCR yet; build it with docker compose as above.
- Clone the repository
- Enable Corepack (uses the
packageManagerfield β pnpm):npm install -g corepack # Node 25+ no longer bundles it corepack enable
- Install dependencies:
pnpm install
- Set up environment variables (see
.env.example) - Start the development server:
pnpm dev
Publishable packages: @crypt.fyi/core and @crypt.fyi/cli (npm), plus the Chrome extension.
- Record changes:
pnpm changeset - Merge to
mainβ the Release workflow opens a Version Packages PR (or publishes when that PR is merged) - Required GitHub secrets for publishing:
NPM_TOKENCHROME_EXTENSION_ID,CHROME_CLIENT_ID,CHROME_CLIENT_SECRET,CHROME_REFRESH_TOKEN,CHROME_PUBLISHER_ID
- Production CSP (including
style-srchashes for sonner/Radix inline styles) lives innginx/nginx.conf vite previewapplies that same policy viapackages/web/csp.tsso local/CI match productionpnpm test:e2eruns Playwright againstvite previewunder that CSP (default createβreadβburn, password unlock). It fails onstyle-src/connect-srcviolations; other console warnings/errors and non-style CSP noise (e.g.script-srceval fallback notes) are reported as non-blocking annotations- The e2e API uses an in-memory rate limiter and dedicated ports (
:4322API /:4173preview by default) so localpnpm devand shared Redis rate-limit keys cannot poison the suite. Playwright rebuilds the web client with that API URL before preview so CSPconnect-srcmatches the baked client config. - When a test fails on style-src, add the reported hash to
nginx/nginx.conf(do not weaken to'unsafe-inline') - Reference: sonner#449
- Ensure Redis is running locally when developing the server
- The web client expects the API to be available at
http://localhost:4321by default - CSP headers in development may differ from production configuration
- Always test encryption/decryption flows thoroughly when making changes
- Ensure no sensitive data is logged or exposed in error messages
- Maintain strict CSP headers to prevent XSS vulnerabilities
- Keep dependencies updated for security patches
Contributions are welcome! Please feel free to submit an Issue or Pull Request on GitHub.