{"id":49889247,"url":"https://github.com/santhsecurity/envseal","last_synced_at":"2026-05-15T20:09:08.853Z","repository":{"id":355668649,"uuid":"1228411360","full_name":"santhsecurity/envseal","owner":"santhsecurity","description":"Secret vault for the agent era. Hardware-sealed at rest, GUI-gated at use, only injected into approved child processes.","archived":false,"fork":false,"pushed_at":"2026-05-04T17:34:50.000Z","size":1570,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-04T19:32:05.406Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://santh.dev","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/santhsecurity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["santhsecurity"]}},"created_at":"2026-05-04T01:41:17.000Z","updated_at":"2026-05-04T17:34:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/santhsecurity/envseal","commit_stats":null,"previous_names":["santhsecurity/envseal"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/santhsecurity/envseal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fenvseal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fenvseal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fenvseal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fenvseal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/santhsecurity","download_url":"https://codeload.github.com/santhsecurity/envseal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fenvseal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33078186,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T20:05:40.333Z","status":"ssl_error","status_checked_at":"2026-05-15T20:05:38.672Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-15T20:09:08.231Z","updated_at":"2026-05-15T20:09:08.845Z","avatar_url":"https://github.com/santhsecurity.png","language":"Rust","funding_links":["https://github.com/sponsors/santhsecurity"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/logo.png\" alt=\"envseal\" width=\"160\" /\u003e\n\u003c/p\u003e\n\n# envseal\n\n[![crates.io](https://img.shields.io/crates/v/envseal-cli.svg?label=envseal-cli)](https://crates.io/crates/envseal-cli)\n[![crates.io](https://img.shields.io/crates/v/envseal-mcp.svg?label=envseal-mcp)](https://crates.io/crates/envseal-mcp)\n[![docs.rs](https://img.shields.io/docsrs/envseal)](https://docs.rs/envseal)\n[![CI](https://github.com/santhsecurity/envseal/actions/workflows/ci.yml/badge.svg)](https://github.com/santhsecurity/envseal/actions/workflows/ci.yml)\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE-MIT)\n\n\u003e ⚠️ **Beta.** Actively hardening toward 1.0. [Try to break it.](SECURITY.md)\n\n\u003e **Hey, thanks for trying envseal.** Small solo project. Core (vault,\n\u003e hardware seal, signal taxonomy, sealed config) is hand-tested on\n\u003e Windows + Linux end-to-end with 900+ unit, regression, property, and\n\u003e adversarial tests, but it hasn't been stress-tested by anyone other\n\u003e than me. If something is awkward, wrong, or surprising,\n\u003e [open an issue](https://github.com/santhsecurity/envseal/issues). I\n\u003e read all of them. The CTF in `envseal ctf start` is the fastest way\n\u003e to attack it; I'll publicly credit anyone who finds something.\n\n\u003e **Recent (0.3.14):** Encrypted audit log (AES-256-GCM events under a\n\u003e per-vault hardware-sealed key), every deferred audit follow-up closed\n\u003e (atomic Windows DACL at create, persistent TOTP rate-limit, homoglyph\n\u003e defense on every dialog field, full symlink-destruction sweep), and\n\u003e the rmcp dependency bumped to 1.6 to clear all open advisories. See\n\u003e [CHANGELOG.md](CHANGELOG.md) and [ROADMAP.md](ROADMAP.md) for what's\n\u003e next.\n\n\u003e **Sudo can't read your keys.** Hardware-sealed at rest, GUI-gated at use, copyable to no other machine.\n\n**envseal** is a developer-first secret vault that turns API keys into\ndevice-bound capabilities. The plaintext exists in exactly two places:\ninside the silicon that minted it (Secure Enclave, TPM, or DPAPI-bound\nuser master), and inside the descendant process you authorized at the\nkeyboard. Nowhere else: not in `cat`, not in `/proc/PID/mem`, not in a\nstolen `master.key`, not in your shell history.\n\n## Why?\n\nIn 2026, AI agents run with full filesystem and shell access. Every `.env` file is readable via `cat .env`. Every API key pasted into a chat window is logged to cloud AI providers. Stack the failure modes:\n\n| Current Defense | Why It Fails |\n|----------------|-------------|\n| `.gitignore` | Prevents commit, not read. |\n| `.cursorignore` | Prompt-based; pushed out of the context window. |\n| OS Keychain | Agent calls `secret-tool lookup` and walks out with plaintext. |\n| Password managers | Authenticate the *user*, not the *program* asking. |\n| `.env` + `dotenv` | Agent runs `cat .env` and the rest is history. |\n| Pasting into chat | Key enters context, logs, and cloud retention. |\n\n**envseal** authenticates the *program*. Secrets can only be released\nto a whitelisted binary, approved via a GUI popup terminal-bound agents\ncannot click, and the wrap key that protects the vault never leaves\nyour physical device.\n\n## The two guarantees\n\n1. **The key cannot leave this machine.** The master key on disk is\n   double-wrapped: passphrase (Argon2id) on the inside, hardware-bound\n   seal on the outside (Windows DPAPI, macOS Secure Enclave, Linux\n   TPM 2.0). Even with `master.key` copied off and the passphrase\n   brute-forced, the file does not decrypt on any other device.\n   `envseal doctor` reports your active tier.\n2. **The key cannot be read without you at the keyboard.** Every\n   release goes through a desktop popup. `sudo`, `ptrace`,\n   `cat /proc/PID/mem`, agent shells with full root: none of them can\n   click \"Allow.\" Headless attackers see only `Error::NoDisplay`.\n\n## Install\n\n### From `cargo` (any platform with Rust 1.77+)\n\n```bash\n# CLI (binary on PATH is `envseal`). RECOMMENDED, fully tested.\ncargo install envseal-cli --locked\n\n# MCP server for AI agents (Claude Desktop, Cursor, Antigravity, Gemini CLI). RECOMMENDED, fully tested.\ncargo install envseal-mcp --locked\n\n# Native desktop app (egui, no JavaScript, no webview). UNTESTED, use at your own risk.\ncargo install envseal-gui --locked\n```\n\n\u003e **Surface status.** The CLI and MCP server are the recommended,\n\u003e production-ready entry points; every release runs them through the\n\u003e full unit / integration / adversarial / property / regression /\n\u003e deep-security / e2e suites. The desktop GUI ships builds but the\n\u003e end-to-end UX flows are not yet covered by automated tests; treat\n\u003e it as a preview until the GUI test harness lands. CLI + MCP have\n\u003e parity for every security-relevant operation, so nothing is gated\n\u003e behind the GUI.\n\nOr from a checkout:\n```bash\ngit clone https://github.com/santhsecurity/envseal\ncd envseal\ncargo install --path cli --locked\ncargo install --path mcp --locked\ncargo install --path desktop-native --locked\n```\n\n### Pre-built binaries\n\nBinary releases for Windows / macOS / Linux are attached to each\n[GitHub release](https://github.com/santhsecurity/envseal/releases).\nDownload the archive for your platform, extract, and place\n`envseal` (and optionally `envseal-mcp`, `envseal-gui`) somewhere\non your `PATH`.\n\n### Optional: keyhog scanner\n\n`envseal scan` and `envseal init --from-history` use the\n[keyhog](https://github.com/santhsecurity/keyhog) scanner when\npresent (896 secret-pattern detectors with GPU acceleration). When\nkeyhog isn't on `PATH`, envseal falls back to a built-in regex\nscanner that covers the common providers. To install:\n```bash\ncargo install keyhog --locked\n```\nkeyhog is intentionally NOT a hard dependency. It pulls in GPU\nruntimes that most envseal users don't want, and the fallback\nregex catches the most common cases. If you operate at scale or\naudit unfamiliar codebases, install keyhog separately.\n\n### First-run setup (one minute)\n\n```bash\n# 1. Verify your platform's protection tier (DPAPI, Secure Enclave, TPM).\nenvseal doctor\n\n# 2. Initialize your vault by storing your first secret. envseal will\n#    prompt for a passphrase via a desktop dialog. Stdin is the only\n#    way values enter the vault; never pass secrets as CLI args.\necho 'sk-proj-…' | envseal store openai-key\n\n# 3. Use it. The first inject pops an approval dialog. Click\n#    \"Allow Always\" and you won't see it again for that binary+secret.\nenvseal inject openai-key=OPENAI_API_KEY -- python app.py\n\n# 4. Other day-to-day operations.\nenvseal list                  # names only, never values\nenvseal peek openai-key       # redacted preview\nenvseal revoke openai-key     # secure zero-fill + delete\n\n# 5. Shell completions (optional).\neval \"$(envseal completions bash)\"   # add to .bashrc\neval \"$(envseal completions zsh)\"    # add to .zshrc\nenvseal completions fish | source    # add to config.fish\n```\n\n### For AI agents (via MCP)\n\nThe agent-native workflow uses `envseal_request_key`. The agent proposes\na key name, a GUI popup appears, the user pastes the value. **The agent\nnever sees the secret.**\n\n```\nAgent: \"I need your Cloudflare API token\"\n       → calls envseal_request_key(\"cloudflare-api\", \"Cloudflare API Token\")\n       → GUI popup: \"Paste your Cloudflare API Token: [________] [Store]\"\nUser:  *copies from dashboard, pastes into popup, clicks Store*\n       → Secret encrypted and stored. Agent receives only \"stored\".\n\nAgent: \"Deploying to Cloudflare...\"\n       → calls envseal_inject(cloudflare-api=CLOUDFLARE_API_TOKEN -- wrangler deploy)\n       → GUI popup: \"Allow wrangler to access cloudflare-api? [Allow Once] [Always Allow] [Deny]\"\nUser:  *clicks Allow Once*\n       → wrangler deploys. Key never touched the chat.\n```\n\n**Same effort as pasting into chat**: 1 paste + 1 click vs 1 paste. The extra click IS the security.\n\n## Security tiers: pick how friction-heavy you want approvals\n\nenvseal ships with three preset tiers. Switch with `envseal security\npreset standard | hardened | lockdown` (or click the tier buttons in\nthe desktop GUI's Settings tab). Detection signals fire the same way\nin every tier; the tier decides what `Action` each `Severity` maps\nto via the policy table at `core/src/guard/signal.rs`.\n\n| Tier | Approval popup | Friction | Default for | Use when… |\n|---|---|---|---|---|\n| **Standard** | Allow Once / Allow Always / Deny | None, instant approval | Daily dev | You trust your shell + the binaries you run |\n| **Hardened** | Same buttons + 2-second pre-popup delay | Anti-click-through delay, virtual keyboard on X11 | CI runners, second laptops | You want a beat to think before approving |\n| **Lockdown** | Same buttons + 5-second delay + 4-digit numeric challenge before each batch | Maximum friction, hard-blocks any `Hostile` signal | High-value vaults, root accounts | You want it to be obviously inconvenient to approve under coercion |\n\nThe tier promotes signal severities through a 5×3 policy matrix. A\n`Severity::Hostile` signal (e.g. `io.stdin.piped`) at Standard\nsurfaces as a friction gate; at Hardened it's a friction gate with\ndelay; at Lockdown it's a hard block. You can override any\n`(severity, tier)` cell or any specific `SignalId` via\n`envseal security override-tier` / `override-signal` (or the\nread-only summary in the desktop GUI's Settings panel).\n\n## Security surface: every toggle, in one place\n\nThese are the knobs that ship with envseal. Most are on by default;\nthe rest you opt into. **Every action is hash-chained into the audit\nlog**, so flipping a setting is itself an event you can review later.\n\n### Approval pipeline\n\n| Knob | Command | What it does |\n| --- | --- | --- |\n| Tier | `envseal security preset \u003cstandard\\|hardened\\|lockdown\u003e` | Sets the entire policy matrix in one shot. Per-cell overrides win over the preset. |\n| Per-signal override | `envseal security override \u003csignal-id\u003e \u003cignore\\|log\\|warn\\|warn_with_challenge\\|block\u003e` | Pin one detector (e.g. `io.stdin.piped`) to a specific action regardless of tier. |\n| Per-tier override | `envseal security override-tier \u003cseverity\u003e:\u003ctier\u003e \u003caction\u003e` | Override one cell of the 5×3 matrix (e.g. `hostile:standard = block`). |\n| List overrides | `envseal security overrides` | Read-only dump of every current override. |\n| Approval delay | `envseal security set approval_delay_secs \u003cN\u003e` | Anti-click-through delay before the popup accepts a click (default 2 s on Hardened, 5 s on Lockdown). |\n| Numeric challenge | `envseal security set challenge_required true` | Require the user to type a 4-digit code shown on screen before approval (default on Lockdown). |\n| Audit logging | `envseal security set audit_logging \u003ctrue\\|false\u003e` | Toggle the hash-chained log. Off only ever for fully-air-gapped CI. |\n| TOTP 2FA | `envseal security totp-setup` / `totp-disable` | Adds an HOTP/TOTP second factor on top of the passphrase for vault unlock. |\n| Relay required | `envseal security set relay_required true` | Refuse local GUI; only accept approvals via the paired-device relay. For headless / SSH workflows. |\n| X11 auto-upgrade | `envseal security set x11_auto_upgrade \u003ctrue\\|false\u003e` | When on X11 (no input isolation), auto-promote to virtual-keyboard input so passphrases can't be `xdotool`-replayed. |\n\n### Always-on hardening (no toggle, it just runs)\n\nThese are not configurable; they're the floor.\n\n- **Vault root validation**: refuses to open in `/tmp`, world-writable\n  dirs, or any path whose component is a symlink. Path-traversal in\n  secret names rejected at parse time.\n- **AES-256-GCM with `name`-bound AAD**: every secret is sealed with\n  its own name as additional authenticated data, so a renamed file on\n  disk fails to decrypt.\n- **Argon2id KDF**: passphrase wrapping uses Argon2id with parameters\n  sized for ≥ 0.5 s on a modern laptop.\n- **Hardware seal**: the wrap key that protects `master.key` is\n  bound to the device's TPM 2.0 / Secure Enclave / Windows DPAPI.\n  Stolen `master.key` won't open on another box.\n- **Self-preload check**: refuses to run if `LD_PRELOAD`,\n  `DYLD_INSERT_LIBRARIES`, or equivalent is set in the inherited env.\n- **Process hardening**: `PR_SET_DUMPABLE(0)`, `RLIMIT_CORE = 0`,\n  `O_CLOEXEC` on every secret FD, `PR_SET_NO_NEW_PRIVS` before exec.\n- **Memory protection**: `memfd_secret()` on Linux 5.14+ unmaps the\n  master key from kernel page tables; `mlock` + `MADV_DONTDUMP`\n  fallback on older kernels; `VirtualLock` on Windows; `mlock` on\n  macOS. Master key zeroized on drop.\n- **Hash-chained audit log**: every event includes the SHA-256 of\n  the previous entry. Tampering breaks the chain; the corrupted file\n  is rotated to `audit.log.corrupted-\u003cts\u003e` and a fresh chain starts.\n- **Policy integrity**: `policy.toml` is HMAC-signed; any unsigned\n  edit rejects subsequent operations until repaired.\n- **Empty-secret refusal**: vault refuses to store a zero-byte\n  value (defends against `cat /dev/null | envseal store creds`).\n- **CTF flag carve-out**: `Vault::decrypt(\"ctf-flag\")` returns\n  `CryptoFailure` unconditionally, audited as\n  `critical [ctf.flag.decrypt_attempt]`. Verify-by-hash only.\n\n### Detection signals (each one fires its own audit event)\n\n| Source | Signal id | Severity | What it catches |\n| --- | --- | --- | --- |\n| `migration.preexec` | `io.stdin.piped` | hostile | A secret value piped into envseal's stdin on a tty session |\n| `migration.preexec` | `io.cmdline.shell_subst` | hostile | `$(…)` / backtick / `eval` in the requesting argv |\n| `guard.gui` | `gui.input_injector` | critical | xdotool / ydotool / xte / wtype running |\n| `guard.gui` | `gui.screen_recorder` | warn | OBS / SimpleScreenRecorder / ffmpeg recording |\n| `guard.gui` | `gui.accessibility_tool` | warn | screen-reader / AT-SPI bridge active |\n| `guard.gui` | `gui.session.ssh` | critical | SSH session, no local display |\n| `guard.gui` | `gui.session.x11_forward` | critical | X11 forwarding, passphrase interceptable |\n| `guard.gui` | `gui.session.remote_desktop` | warn | RDP / VNC session detected |\n| `guard.env` | `env.loader.preload` | critical | `LD_PRELOAD` or peer set in inherited env |\n| `vault.entropy` | `secret.entropy.too_short` | warn | secret \u003c 8 bytes |\n| `vault.entropy` | `secret.entropy.low_shannon` | warn | low Shannon entropy for its length |\n| `vault.entropy` | `secret.entropy.placeholder.\u003cword\u003e` | warn | matches `todo`, `changeme`, `your-api-key`, … |\n| `audit.chain` | `audit.chain.rotated_corruption` | critical | tamper-detected log was rotated |\n| `vault.binary` | `binary.tampered` | critical | approved binary's hash no longer matches |\n| `vault.policy` | `policy.tampered` | critical | `policy.toml` HMAC mismatch |\n| `vault.dpapi` | `vault.dpapi.device_mismatch` | critical | `master.key` wrap was minted on a different device |\n| `ctf` | `ctf.flag.decrypt_attempt` | critical | something tried to read the CTF flag |\n| `ctf` | `ctf.verify.incorrect` | info | wrong flag submitted |\n\nEvery signal renders to stderr at the time it fires AND is appended\nto the audit log. `envseal audit --json` gives the full structured\nstream; `envseal security overrides` shows the action you've pinned\nfor each.\n\n### Sandbox tiers (for `supervised`)\n\n`envseal supervised \u003cname\u003e=\u003cVAR\u003e [--sandbox=\u003ctier\u003e] -- \u003ccmd\u003e` runs\nthe child under live leak-detection AND, optionally, a sandbox:\n\n| Sandbox tier | Linux | macOS | Windows |\n| --- | --- | --- | --- |\n| `none` (default) | observe only | observe only | observe only |\n| `standard` | seccomp filter (no `ptrace`, no `process_vm_readv`) | `sandbox_init` `pure-computation` profile | Job Object with restricted handle access |\n| `hardened` | + new pid/mount/uts namespaces | + restricted-network profile | + restricted desktop |\n| `lockdown` | + read-only root, no network namespace | + filesystem-read-only profile | + integrity-low token |\n\nThe supervisor inspects child stdout/stderr in real time; any\nsubstring match for a known secret value triggers\n`supervisor_leak_detected` and terminates the child.\n\n## CTF: try to break it. Publicly credited if you do.\n\nOnce a secret enters the vault, the claim is: **nobody gets it\nout.** Not a human, not an AI agent, not both working together.\n\n```bash\nenvseal ctf start    # generates ENVSEAL_CTF{...}, seals it, switches the vault to Lockdown\nenvseal ctf rules    # what's allowed, what's banned (only DMA / cold-boot / JTAG are off-limits)\nenvseal ctf status   # check active challenge + verification hash\nenvseal ctf verify \u003cflag\u003e   # submit a guess\nenvseal ctf reset    # clean up + restore your pre-CTF tier\n```\n\n**What's allowed:** memory reading (`/proc/pid/mem`, `process_vm_readv`,\n`ptrace`), binary replacement, PATH poisoning, `LD_PRELOAD`, GUI\nautomation tools (xdotool, ydotool, xte, libinput replay), config\ntampering, side channels (timing/cache/power), kernel modules,\nsandbox escape, race conditions, TOCTOU, anything creative in\nsoftware.\n\n**What's banned**: only physical hardware attacks (DMA via\nThunderbolt/PCIe, cold-boot RAM transplant, JTAG). Those bypass\nsoftware on every machine, not just envseal.\n\n**Reward:** Hall of Fame in `SECURITY.md` + writeup credit. There's\nno bug-bounty cash because this is a one-person project, but if you\ndemonstrate a Tier 1 break (extract the flag from a Lockdown vault),\nthe writeup will be the public record of envseal's first failure\nmode, high-prestige finding.\n\n## MCP server setup\n\nenvseal ships an MCP (Model Context Protocol) server that lets AI\nagents store, list, inject, and verify secrets without ever seeing\nplaintext. Each tool call surfaces a GUI approval popup that the\nhuman authorizes; the agent only sees `OK` or `denied`.\n\nRun `which envseal-mcp` to get the absolute path of the binary\ninstalled by `cargo install envseal-mcp` (or by extracting the\nrelease archive to your `PATH`). Every config below needs it\n(replace `/path/to/envseal-mcp`).\n\n#### Claude CLI (Claude Code)\n\n```bash\nclaude mcp add envseal /path/to/envseal-mcp\n```\n\nOr edit `~/.claude.json` and add to `mcpServers`:\n\n```json\n{\n  \"mcpServers\": {\n    \"envseal\": {\n      \"command\": \"/path/to/envseal-mcp\"\n    }\n  }\n}\n```\n\n#### Gemini CLI\n\nEdit `~/.gemini/settings.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"envseal\": {\n      \"command\": \"/path/to/envseal-mcp\"\n    }\n  }\n}\n```\n\nGemini CLI requires **absolute** paths; `~` expansion is not honored.\n\n#### Cursor / Antigravity / generic MCP-aware editor\n\nAdd to your editor's MCP config (typically `~/.cursor/mcp.json` or\n`~/.antigravity/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"envseal\": {\n      \"command\": \"/path/to/envseal-mcp\"\n    }\n  }\n}\n```\n\n#### Verify the MCP server is wired up\n\nAfter restarting your agent, ask it: \"list the envseal tools you have\".\nThe agent should enumerate `envseal_store`, `envseal_inject`,\n`envseal_list`, `envseal_audit`, `envseal_doctor`, etc. If it says it has\nno envseal tools, the path in the MCP config is wrong or the binary is\nnot executable. Try `chmod +x /path/to/envseal-mcp` and check the agent's\nMCP startup log.\n\nPer-agent web walkthroughs: [docs/setup/](docs/setup/) has copy-pasteable\nagent-specific prompts (Cursor, Antigravity, Gemini CLI, Claude CLI,\nmanual) for the same configuration.\n\n## The `.envseal` File\n\nDrop-in `.env` replacement. **Safe to commit to git**: contains references, not values:\n\n```bash\n# .envseal: safe to commit\nDATABASE_URL=database-url\nREDIS_URL=redis-url\nOPENAI_API_KEY=openai-key\nSTRIPE_SECRET_KEY=stripe-key\n```\n\n```bash\n# Generate from existing vault secrets\nenvseal init\n\n# Run your app\nenvseal inject-file .envseal -- npm run dev\n```\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `envseal store \u003cname\u003e [--force] [--gui]` | Store a secret (stdin or GUI popup) |\n| `envseal request-key \u003cname\u003e [--description d]` | Agent-initiated GUI key request |\n| `envseal inject \u003cname\u003e=\u003cVAR\u003e -- \u003ccmd\u003e` | Inject secret into a process |\n| `envseal inject-file \u003cpath\u003e -- \u003ccmd\u003e` | Inject all secrets from `.envseal` file |\n| `envseal run -- \u003ccmd\u003e [args...]` | Run command with explicit `.envseal` mappings |\n| `envseal shell [--login]` | Open subshell with mapped secrets injected |\n| `envseal pipe \u003cname\u003e -- \u003ccmd\u003e` | Deliver a single secret on the child's stdin (no env var) |\n| `envseal supervised \u003cname\u003e=\u003cVAR\u003e [--sandbox=\u003ctier\u003e] -- \u003ccmd\u003e` | Run with real-time leak detection and optional sandbox tier (`standard`, `hardened`, `lockdown`) |\n| `envseal scan [--deep] [--path \u003cdir\u003e]` | Scan dotfiles + cwd `.env*` (or whole `$HOME` with `--deep`); uses `keyhog` if installed |\n| `envseal scan --system` | Hand off to `keyhog scan-system`. Every mounted drive + every git history (needs keyhog). |\n| `envseal` *(no args)* / `envseal tui` | Open the interactive terminal UI (Welcome, Quickstart, Secrets, Doctor, Scanner, Audit, CTF) |\n| `envseal import \u003c.env\u003e [--delete]` | Migrate from `.env` to envseal |\n| `envseal init [path]` | Scaffold `.envseal` project file |\n| `envseal doctor` | System security readiness check |\n| `envseal status [--json]` | Show vault status (tier, secret count, etc.) |\n| `envseal list` | List secret names (never values) |\n| `envseal peek \u003cname\u003e` | Show a redacted preview of a secret |\n| `envseal revoke \u003cname\u003e` | Secure delete a secret |\n| `envseal copy \u003cfrom\u003e \u003cto\u003e` | Duplicate a secret |\n| `envseal rename \u003cfrom\u003e \u003cto\u003e` | Rename a secret |\n| `envseal alias \u003ccmd...\u003e` | Generate shell aliases that wrap `envseal run` |\n| `envseal policy show` | Show whitelist rules |\n| `envseal policy revoke-binary \u003cpath\u003e` | Remove rules for a binary |\n| `envseal audit [N]` | Show last `N` audit log entries |\n| `envseal security show\\|set\\|preset` | Manage security configuration tiers |\n| `envseal health [--max-age=N]` | Secret health/compliance report |\n| `envseal git-hook \u003cinstall\\|show\\|gitignore\u003e` | Install and inspect leak-prevention hook |\n| `envseal hook \u003cinstall\\|uninstall\\|show\\|status\u003e [bash\\|zsh\\|fish]` | Manage the shell preexec hook that captures typed keys |\n| `envseal init --from-history` | Migrate every secret previously typed at the shell |\n| `envseal op run -- \u003ccmd\u003e` / `envseal doppler run -- \u003ccmd\u003e` / `envseal vault run -- \u003ccmd\u003e` | Drop-in compatibility shims for 1Password / Doppler / HashiCorp Vault CLI surface |\n| `envseal emergency-revoke` | Wipe all secrets from the vault |\n| `envseal ctf \u003cstart\\|verify\\|rules\\|status\u003e` | CTF challenge workflows |\n| `envseal completions \u003cbash\\|zsh\\|fish\u003e` | Generate shell completions |\n\n## Threat model\n\nThe full defense list lives under\n[Always-on hardening](#always-on-hardening-no-toggle-it-just-runs)\nabove. This table is the operator-facing version: who can read a\nsecret today, and who cannot.\n\n**Zero network connections.** envseal makes none. No telemetry, no\nupdate checks, no cloud accounts.\n\n| Attacker | Access? |\n|----------|---------|\n| AI agent with terminal access | No, cannot interact with GUI popup |\n| Malicious script in build pipeline | No, binary not whitelisted |\n| Root user (ptrace/proc) | No, `memfd_secret` + `PR_SET_DUMPABLE(0)` |\n| Stolen `master.key` on attacker's machine | No, hardware seal refuses on a different device |\n| Brute-force passphrase against stolen `master.key` | No, without the device's TPM/SEP/DPAPI key the wrap doesn't open |\n| Human at the keyboard | Yes, can approve via GUI |\n| Remote desktop attacker | Partial, detected via `assess_gui_security()` |\n| Supply chain (npm token theft) | No, token never enters agent context |\n\n### GUI Security Assessment\n\nenvseal continuously monitors the GUI environment:\n\n- **Remote session detection**: SSH, X11 forwarding, RDP/VNC\n- **Input injection detection**: xdotool, ydotool, xte, wtype\n- **Screen recording detection**: OBS, SimpleScreenRecorder, ffmpeg\n- **Threat classification**: Safe / Degraded / Hostile\n\n### Platform Support\n\n| Platform | GUI Backend | Hardware Seal | In-Memory | Sandbox | Status |\n|----------|-------------|---------------|-----------|---------|--------|\n| Linux | zenity / kdialog | TPM 2.0 (via tpm2-tools, optional) | `memfd_secret` (5.14+) | unshare namespaces (Hardened/Lockdown) | Supported |\n| macOS | osascript | Secure Enclave (P-256, ECIES) | mlock | `sandbox_init` profiles | Supported |\n| Windows | PowerShell Forms | DPAPI (TPM-rooted on Win10+) | VirtualLock | Job Objects | Supported |\n\n## Migrating from `.env`, `op`, `doppler`, or your shell history\n\nenvseal is built to be the cheapest path off whatever you're using today. Pick the entry point that matches how the secrets are leaking:\n\n```bash\n# 1. Bulk migrate a .env file\nenvseal import .env --delete\n\n# 2. Migrate everything you've already typed at the prompt\nenvseal init --from-history          # scans bash/zsh/fish history,\n                                     # imports each detected key into the vault\n\n# 3. Live-capture future keys without thinking about it\nenvseal hook install                 # auto-detects $SHELL,\n                                     # writes a preexec hook into .bashrc/.zshrc/.config/fish/config.fish\n# Now whenever you type:\n#   OPENAI_API_KEY=sk-... node app.js\n# envseal pops a \"store this for next time?\" dialog before the command runs.\n\n# 4. Drop-in for existing scripts that called op / doppler / vault\nenvseal op run -- node app.js                    # 1Password CLI shape\nenvseal doppler run --config dev -- npm run dev  # Doppler shape\nenvseal vault run -- ./deploy.sh                 # HashiCorp Vault shape\n```\n\nAfter migration, `envseal run -- \u003ccmd\u003e` reads the nearest `.envseal` file and injects every reference. (See [The `.envseal` File](#the-envseal-file) above for the format.)\n\n## Desktop app (preview, untested)\n\nThe `envseal-gui` binary in `desktop-native/` is a pure-Rust **egui/eframe** app (no webview) covering the read-only views the CLI exposes. As noted in [Install](#install) above, the GUI is not yet covered by the automated test suites. Tabs:\n\n- **Dashboard**: Overview of vault state and recent activity\n- **Secrets**: View and revoke stored secrets\n- **Store**: Encrypt new secrets via the GUI\n- **Policy**: View and revoke binary access rules\n- **Settings**: Security tier, input protection, and threat assessment\n- **Audit**: Session activity tracking\n- **Health**: Secret health and compliance report\n- **Scanner**: Scan for leaked secrets and misconfigurations\n\n## Vulnerability reports\n\nBeyond the CTF, we welcome vulnerability reports at any tier, from GUI\nbypass to crypto weakness. See **[SECURITY.md](SECURITY.md)** for the\n3-tier disclosure program and how to submit findings.\n\n## Roadmap \u0026 contributing\n\nWhat's in flight, what's queued, and (importantly) a list of\nwell-scoped items we'd love outside contributors to take on. From\n\"add a regex pattern\" to \"build the watchdog process that monitors\nenvseal's heartbeats and detects spoofed popups,\" there's something\nat every experience level.\n\n**→ [ROADMAP.md](ROADMAP.md)**: the full living roadmap, with claim\ninstructions and Hall-of-Fame credit for shipped contributions.\n\nA few highlights currently open for community work:\n\n- **Heartbeat \u0026 watchdog process**: a separate lightweight monitor\n  that consumes signed heartbeats from envseal, observes OS popup\n  events, and alerts on anomalies. Out-of-tree by design; a great\n  systems-programming entry point.\n- **Telegram-bot relay**: phone approvals via inline buttons, no\n  envseal mobile app required.\n- **`cargo fuzz` harness for the v3 envelope parser**: `core/fuzz/`\n  is primed for it.\n- **Reproducible-build verifier**: independently rebuild a release\n  tag and confirm byte-for-byte equivalence.\n- **Documentation translation**: wider reach in non-English-speaking\n  dev communities.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the dev setup and merge\nbar; ROADMAP.md has the architectural context for each item.\n\n## License\n\nMIT OR Apache-2.0\n\n## About\n\nBuilt by [Santh](https://santh.dev).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanthsecurity%2Fenvseal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsanthsecurity%2Fenvseal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanthsecurity%2Fenvseal/lists"}