
Sicherer, ephemerer Geheimnisaustausch für Entwickler.
Sicheres, flüchtiges Teilen von Geheimnissen für Entwickler.
Hör auf, Geheimnisse in Slack zu kopieren. enseal macht den sicheren Weg schneller als den unsicheren — teile .env-Dateien und Geheimnisse über verschlüsselte, einmalig nutzbare Kanäle mit einem Befehl und ohne Einrichtung.```bash
$ enseal share .env Share code: 7-guitarist-revenge Secrets: 14 variables (staging) Expires: on first receive
$ enseal receive 7-guitarist-revenge ok: 14 secrets written to .env
## Installation
### Von crates.io```bash
cargo install enseal
git clone https://github.com/FlerAlex/enseal.git cd enseal cargo build --release
### Vorgefertigte Binärdateien
Herunterladen von [GitHub Releases](https://github.com/FlerAlex/enseal/releases) für Linux (x86_64, aarch64), macOS (Intel, Apple Silicon) und Windows.
## Schnellstart
### Anonymer Modus (keine Einrichtung)
Teilen Sie Geheimnisse mit einem Einmalcode. Keine Schlüssel, keine Konten – funktioniert sofort.```bash
# terminal 1 (sender)
enseal share .env
Share code: 7-guitarist-revenge
Secrets: 14 variables
Expires: on first receive
# terminal 2 (recipient) — enter the code
enseal receive 7-guitarist-revenge
ok: 14 secrets written to .env
Funktioniert auch mit einzelnen Geheimnissen:```bash
echo "my-api-token" | enseal share --label "API key" Share code: 4-orbital-hammock
enseal receive 4-orbital-hammock my-api-token
Beide Terminals müssen gleichzeitig geöffnet sein — der Sender wartet, bis der Empfänger eine Verbindung herstellt.
### Identitätsmodus (schlüsselbasiert, keine Codes)
Für Teams mit etabliertem Schlüsselvertrauen. Verschlüsseln Sie auf einen Namen, keine Koordination erforderlich.```bash
# one-time setup
enseal keys init
enseal keys export > my-key.pub # share this with teammates
enseal keys import teammate-key.pub # import theirs
# sender encrypts to recipient by name
enseal share .env --to sarah
# or push through the public relay (no codes at all)
enseal share .env --to sarah --relay wss://relay.enseal.dev
# or produce an encrypted file (no network)
enseal share .env --to sarah --output ./drop/
enseal inject 7-guitarist-revenge -- npm start
enseal inject --listen --relay wss://relay.enseal.dev -- docker compose up
enseal inject ./staging.env.age -- python manage.py runserver
Geheimnisse existieren nur im Speicher des untergeordneten Prozesses. Wenn er endet, sind sie verschwunden.
## Funktionen
### Drei Freigabemodi
**Anonymer Modus** (Standard) — wormhole-basiert, keine Einrichtung erforderlich. Ein lesbarer Code ist alles, was Sie brauchen. Gegenseitige SPAKE2-Authentifizierung verhindert MITM-Angriffe.```bash
enseal share .env # generates wormhole code
enseal receive 7-guitarist-revenge # uses code
Mit --relay umgeht der anonyme Modus das Wormhole und verwendet stattdessen den enseal-Relay-Transport. Beide Seiten müssen dasselbe Relay verwenden:```bash
enseal share .env --relay ws://relay.internal:4443 # generates channel code
enseal receive 3421-amber-frost --relay ws://relay.internal:4443
**Async upload (`--upload`)** — nur für den Sender. Verschlüsselt lokal und veröffentlicht auf [burnurl.dev](https://burnurl.dev) und gibt eine selbstzerstörende URL zurück, die der Empfänger in einem Browser öffnet. Auf der Empfängerseite ist keine CLI erforderlich.```bash
enseal share .env --upload
# Secret URL: https://burnurl.dev/s/a3f9c2e1...
# Expires: 2026-03-08 19:42:00 UTC (24h)
# Reads: 1 (self-destructs on first open)
Der Empfänger öffnet die URL in einem beliebigen Browser – keine enseal-Installation erforderlich. Fügen Sie --passphrase hinzu, um vor dem Hochladen clientseitig zu verschlüsseln (der Server sieht nur den Chiffretext):```bash
enseal share .env --upload --passphrase # prompts for passphrase
enseal share .env --upload --ttl 4 # 4-hour TTL (max 24)
API-Zugriff erfordert einen Pro- oder Team-Tarif auf burnurl.dev. Setzen Sie `BURNURL_API_KEY` auf Ihren Schlüssel. Überschreiben Sie die Basis-URL für selbst gehostete Instanzen: `BURNURL_URL=https://burnurl.internal`.
**Identitätsmodus** — Public-Key-Verschlüsselung für bekannte Teammitglieder. Verschlüsseln an einen Namen.```bash
enseal keys init # one-time setup
enseal share .env --to sarah # encrypt to sarah's public key
Der Identitätsmodus unterstützt drei Transportoptionen:```bash
enseal share .env --to sarah
enseal share .env --to sarah --relay wss://relay.enseal.dev
enseal share .env --to sarah --output ./drop/
### Flexible Eingabe
enseal akzeptiert Geheimnisse aus mehreren Quellen:```bash
# .env file (default)
enseal share .env
enseal share staging.env
# environment profile
enseal share --env staging # resolves to .env.staging
# pipe from stdin
echo "sk_live_abc123" | enseal share
cat secrets.env | enseal share
pass show stripe/key | enseal share --to sarah
# inline (careful — visible in shell history)
enseal share --secret "API_KEY=sk_live_abc123"
# wrap raw string as KEY=VALUE
echo "sk_live_abc123" | enseal share --as STRIPE_KEY
${VAR}-Referenzen werden vor dem Senden aufgelöst, sodass die Empfänger vollständig erweiterte Werte erhalten:```env
DB_HOST=postgres.internal
DB_PORT=5432
DATABASE_URL=postgres://user:pass@${DB_HOST}:${DB_PORT}/myapp
Unterstützt die Fallback-Syntax `${VAR:-default}`. Zirkuläre und Vorwärtsreferenzen werden erkannt und zurückgewiesen. Verwenden Sie `--no-interpolate`, um die rohe `${VAR}`-Syntax zu senden.
### Filtern
Steuern Sie, welche Variablen gesendet werden:```bash
# exclude public/non-secret vars
enseal share .env --exclude "^PUBLIC_|^NEXT_PUBLIC_"
# send only matching vars
enseal share .env --include "^DB_|^API_"
# skip .env parsing entirely (send raw file)
enseal share .env --no-filter
Die Ausgabe passt sich an das Gesendete an:```bash
enseal receive CODE ok: 14 secrets written to .env
enseal receive CODE --output staging.env
enseal receive CODE sk_live_abc123
enseal receive CODE --clipboard ok: copied to clipboard
enseal receive CODE --no-write
enseal receive ./staging.env.age ok: signature verified, file decrypted ok: 14 secrets written to .env
### Injizieren
Empfange Geheimnisse und injiziere sie direkt als Umgebungsvariablen in einen Kindprozess. Geheimnisse berühren niemals das Dateisystem.```bash
# anonymous mode: inject via wormhole code
enseal inject 7-guitarist-revenge -- npm start
# identity mode: listen for incoming transfer on relay
enseal inject --listen --relay wss://relay.enseal.dev -- docker compose up
# from encrypted file drop
enseal inject ./staging.env.age -- python manage.py runserver
Mit --listen verbindet sich der Empfänger mit dem Relay und wartet. Der Sender überträgt mit enseal share .env --to alex --relay wss://relay.enseal.dev — kein Austausch von Codes, keine Koordination nötig.
enseal check error: missing from .env (present in .env.example): JWT_SECRET, REDIS_URL
enseal diff .env.development .env.staging
enseal redact .env DATABASE_URL= API_KEY= PORT=
enseal validate .env error: missing required: JWT_SECRET error: PORT value "abc" is not an integer ok: 11/14 variables passed validation
enseal template .env
### Verschlüsselung im Ruhezustand
Verschlüsseln Sie `.env`-Dateien für sichere Git-Speicherung mit age-Verschlüsselung:```bash
# whole-file encryption
enseal encrypt .env
ok: .env encrypted in-place (14 variables, age key)
enseal decrypt .env
# per-variable: keys visible for diffing, values encrypted
enseal encrypt .env --per-var
# DB_HOST=ENC[age:abc123...]
# DB_PORT=ENC[age:def456...]
# multi-recipient: anyone on the team can decrypt
enseal encrypt .env --to sarah --to alex
enseal keys init
enseal keys export > my-key.pub
enseal keys import sarah.pub
enseal keys list
enseal keys fingerprint
enseal keys remove [email protected]
enseal keys alias sarah [email protected]
enseal keys group create backend-team enseal keys group add backend-team sarah enseal keys group add backend-team alex enseal keys group list backend-team enseal share .env --to backend-team
enseal keys group delete backend-team
### Öffentlicher Relay
Ein kostenloser öffentlicher Relay ist verfügbar unter `wss://relay.enseal.dev`. Verwenden Sie ihn für schnelle Tests oder wenn Sie keinen privaten Relay benötigen.```bash
# check relay health
curl https://relay.enseal.dev/health
# use it for identity-mode transfers
enseal share .env --to sarah --relay wss://relay.enseal.dev
enseal inject --listen --relay wss://relay.enseal.dev -- npm start
# or set it globally
export ENSEAL_RELAY=wss://relay.enseal.dev
enseal keys init
enseal keys export > /tmp/mykey.pub enseal keys import /tmp/mykey.pub
enseal share --secret "TEST=works" --to mykey --output /tmp/ enseal receive /tmp/mykey.env.age
enseal inject --listen --relay wss://relay.enseal.dev -- env | grep TEST
enseal share --secret "TEST=relay_works" --to mykey --relay wss://relay.enseal.dev
### Selbst gehosteter Relay
Behalten Sie alles in Ihrem Netzwerk. Der Relay ist zustandslos — er sieht nur Chiffretext.```bash
# Docker (one command)
docker run -d -p 4443:4443 enseal/relay
# Or as a binary
enseal serve --port 4443
# Check relay health
curl http://localhost:4443/health
enseal serve spricht einfaches WebSocket (ws://). Für TLS setzen Sie einen Reverse-Proxy (Caddy, nginx) davor und verbinden Sie sich mit wss://.
Mit gesetztem --relay leiten alle Modi über Ihren Relay:```bash
enseal share .env --relay ws://relay.internal:4443
enseal receive 3421-amber-frost --relay ws://relay.internal:4443
export ENSEAL_RELAY=ws://relay.internal:4443 enseal share .env
Identitätsmodus mit einem selbst gehosteten Relay ist vollständig codefrei:```bash
# receiver listens on the relay
enseal inject --listen --relay ws://relay.internal:4443 -- npm start
# sender pushes directly — no code generated
enseal share .env --to alex --relay ws://relay.internal:4443
ok: pushed to alex
Definieren Sie Regeln in .enseal.toml im Projektstamm:```toml
[schema]
required = ["DATABASE_URL", "API_KEY", "JWT_SECRET"]
[schema.rules.DATABASE_URL] pattern = "^postgres://" description = "PostgreSQL connection string"
[schema.rules.PORT] type = "integer" range = [1024, 65535]
[schema.rules.API_KEY] min_length = 32
Dann validieren:```bash
enseal validate .env
Validierung läuft auch automatisch beim Empfang von .env-Dateien — defekte Konfigurationen werden abgefangen, bevor sie Verwirrung stiften.
enseal share --env staging # shares .env.staging enseal validate --env production # validates .env.production enseal diff .env.development .env.production
## Funktionsweise
### Anonymer Modus
**Wormhole (Standard, ohne `--relay`):**
1. Der Absender verschlüsselt die Nutzlast mit `age`
2. Ein SPAKE2-Schlüsselaustausch etabliert ein gemeinsames Geheimnis über das öffentliche Wormhole-Relay
3. Die verschlüsselte Nutzlast wird durch das Relay geleitet
4. Der Empfänger entschlüsselt mit dem ausgehandelten Schlüssel
5. Der Kanal wird zerstört — einmalige Nutzung, zeitlich begrenzt
Das Relay sieht niemals Klartext. Der Wormhole-Code bietet gegenseitige Authentifizierung.
**Enseal-Relay (`--relay`):**
1. Der Absender verschlüsselt die Nutzlast mit `age` und sendet sie unter einem generierten Kanalkode an das Enseal-Relay
2. Der Empfänger verbindet sich mit demselben Code mit demselben Relay und empfängt die Nutzlast
3. Der Kanal wird beim ersten Empfang verbraucht
In diesem Modus gibt es kein SPAKE2 — der Kanalkode ist die einzige Berechtigung.
### Asynchroner Upload (`--upload`)
1. Der Absender serialisiert die Nutzlast in ein `Envelope` (JSON, SHA-256-Integritätsprüfung)
2. Verschlüsselt sie optional clientseitig mit einer age scrypt-Passphrase (`--passphrase`)
3. Sendet die Nutzlast per POST an `burnurl.dev/api/secret` über HTTPS
4. burnurl.dev speichert sie serverseitig mit AES-256-GCM im Ruhezustand (at rest) und gibt eine Self-Destruct-URL zurück
5. Die URL ist für die konfigurierte TTL gültig (bis zu 24h im kostenlosen Tarif), nur einmal lesbar
Der Absender teilt die URL. Der Empfänger öffnet sie in einem beliebigen Browser — kein Enseal erforderlich. Mit `--passphrase` muss die Passphrase separat geteilt werden; der Server sieht niemals Klartext.
**Tarife:** Für den API-Zugriff ist ein Pro- oder Team-Plan auf burnurl.dev erforderlich. Setzen Sie `BURNURL_API_KEY` auf Ihren Schlüssel — der kostenlose Tarif hat keinen API-Zugriff.
Überschreiben Sie `BURNURL_URL`, um auf eine selbst gehostete burnurl-Instanz zu verweisen.
### Identitätsmodus (Öffentlicher Schlüssel)
1. Der Absender verschlüsselt mit dem öffentlichen `age`-Schlüssel des Empfängers
2. Der Absender signiert mit seinem eigenen `ed25519`-Schlüssel
3. Die Nutzlast wird durch Relay, File Drop oder Wormhole geleitet
4. Der Empfänger entschlüsselt mit seinem privaten Schlüssel
5. Der Empfänger überprüft die Signatur des Absenders
Vertrauen basiert darauf, welche Schlüssel Sie importiert haben.
**Transportoptionen im Identitätsmodus:**
| Transport | Flag | Funktionsweise |
|---|---|---|
| Wormhole (Standard) | `--to sarah` | Generiert einen Code, wie im anonymen Modus, aber mit Signierung |
| Relay-Push | `--to sarah --relay URL` | Pusht in den deterministischen Kanal des Empfängers, kein Code |
| File Drop | `--to sarah --output ./dir/` | Erzeugt verschlüsselte `.env.age`-Datei, kein Netzwerk |
Beim Relay-Push hört der Empfänger mit `enseal inject --listen --relay URL -- cmd` mit oder empfängt den File Drop mit `enseal receive ./file.env.age`.
## Sicherheitsmodell
**Geschützt:**
- Geheimnisse während der Übertragung (verschlüsselter Kanal)
- Geheimnisse im Slack/E-Mail-Verlauf (flüchtig, keine Persistenz)
- MITM-Angriffe (SPAKE2 / Public-Key-Authentifizierung)
- Bösartiges Relay (Ende-zu-Ende-Verschlüsselung, Relay sieht nur Chiffretext)
- Identitätsdiebstahl des Absenders (Identitätsmodus: ed25519-Signaturen)
- Geheimnisse auf der Festplatte (Inject-Modus: nur im Prozessspeicher)
- Geheimnisse in Git (Verschlüsselung im Ruhezustand)
**Nicht geschützt:**
- Kompromittierte Endpunkte (wenn die Maschine kompromittiert ist, hilft nichts)
- Schlüsselverteilung (Sie vertrauen den importierten Schlüsseln — keine PKI, keine CA)
## Konfiguration
Optionale `.enseal.toml`-Datei im Stammverzeichnis Ihres Projekts:```toml
[defaults]
relay = "wss://relay.enseal.dev" # public relay (identity mode)
# relay = "ws://relay.internal:4443" # self-hosted without TLS
# relay = "wss://relay.internal:4443" # self-hosted with TLS reverse proxy
[filter]
exclude = ["^PUBLIC_", "^NEXT_PUBLIC_", "^REACT_APP_"]
[identity]
default_recipient = "devops-team"
[schema]
required = ["DATABASE_URL", "API_KEY", "JWT_SECRET"]
CORE
enseal share [] Send secrets (file, pipe, or --secret)
enseal receive [<code|file>] Receive secrets
enseal inject [] -- Inject secrets into a process
enseal keys Manage identity keys and aliases
enseal serve Run self-hosted relay server
.ENV TOOLKIT enseal check [file] Verify .env has all vars from .env.example enseal diff Compare .env files (keys only) enseal redact Replace values with enseal validate Validate against schema rules enseal template Generate .env.example with type hints
ENCRYPTION enseal encrypt Encrypt .env for git storage enseal decrypt Decrypt an encrypted .env
### `share` Flags```
--to <name> Identity mode: encrypt to recipient (alias, group, or identity)
--output <dir> File drop: write encrypted file (identity mode, no network)
--upload Post to burnurl.dev (async, browser-readable, no CLI on recipient side)
--ttl <hours> Secret TTL for --upload (1-24, default: 24)
--passphrase Encrypt client-side before --upload (prompts; server never sees plaintext)
--secret <value> Inline secret (raw string or KEY=VALUE)
--label <name> Human label for raw/piped secrets
--as <KEY> Wrap raw input as KEY=<value>
--relay <url> Route through relay server. Anonymous mode: uses enseal relay transport
(generates channel code, bypasses wormhole). Identity mode: push to
recipient's channel. Also: ENSEAL_RELAY env var.
--env <profile> Environment profile (resolves to .env.<profile>)
--exclude <pattern> Regex to exclude vars
--include <pattern> Regex to include only matching vars
--no-filter Send raw file, skip .env parsing
--no-interpolate Don't resolve ${VAR} references before sending
--words <n> Words in wormhole code (2-5, default: 2). Wormhole mode only (no --relay).
--quiet / -q Minimal output
receive Flaggen```--output Write to specific file --clipboard Copy to clipboard instead of stdout/file --no-write Print to stdout even for .env payloads --relay Use specific relay server --quiet / -q Minimal output
### `inject` Flags```
--listen Listen for incoming identity-mode transfer (requires --relay)
--relay <url> Use specific relay server (also: ENSEAL_RELAY)
--quiet / -q Minimal output
keys Unterbefehle```enseal keys init Generate your keypair enseal keys export Print your public key bundle enseal keys import Import a colleague's public key enseal keys list Show all trusted keys and aliases enseal keys remove Remove a trusted key enseal keys fingerprint Show your key fingerprint enseal keys alias Map short name to identity enseal keys group create Create a named group enseal keys group add Add identity to group enseal keys group remove Remove identity from group enseal keys group list [name] List groups or group members enseal keys group delete Delete a group
### `serve` Optionen```
--port <port> Listen port (default: 4443)
--bind <addr> Bind address (default: 0.0.0.0)
--max-mailboxes <n> Max concurrent channels (default: 100)
--channel-ttl <seconds> Idle channel lifetime (default: 300)
--max-payload <bytes> Max WebSocket message size (default: 1048576)
--rate-limit <n> Max connections per minute per IP (default: 10)
--health Print server health check and exit
encrypt / decrypt Flags```--per-var Per-variable encryption (keys visible, values encrypted) --to Encrypt to specific recipients (multi-key)
### Globale Flags```
--verbose / -v Debug output (never prints secret values)
--quiet / -q Minimal output (for scripting)
| enseal | Slack DM | 1Password Share | dotenvx | croc | |
|---|---|---|---|---|---|
| Keine Einrichtung | Ja | Ja | Nein | Nein | Ja |
| Ende-zu-Ende verschlüsselt | Ja | Nein | Ja | N/A | Ja |
| Ephemer (kein Verlauf) | Ja | Nein | Ja | N/A | Ja |
| .env-bewusst | Ja | Nein | Nein | Ja | Nein |
| Prozessinjektion | Ja | Nein | Nein | Ja | Nein |
| Schema-Validierung | Ja | Nein | Nein | Nein | Nein |
| Ruhende Verschlüsselung | Ja | N/A | N/A | Ja | Nein |
| Selbst hostbarer Relay | Ja | Nein | Nein | N/A | Ja |
| Unterstützung für Rohstrings/Pipes | Ja | Ja | Nein | Nein | Ja |
--to-Flag (erledigt)--upload) (aktuell)MIT