Environment Injection Architecture
While the Credential Proxy provides total zero-exposure security for HTTP traffic, modern development stacks frequently rely on tools, database drivers, and SDKs that require credentials in operating system environment variables (os.environ / process.env).
Traditionally, developers solve this by writing .env files to disk or running export KEY=value in their terminal. Both approaches introduce severe security vulnerabilities:
- Plaintext Disk Exposure: Any background process, malicious package dependency, or autonomous AI agent with filesystem read access can read
.envfiles. - Shell Environment Pollution: Running
export KEY=valuepersists secrets in your interactive terminal session, writes them into shell history files (~/.bash_history,~/.zsh_history), and leaks them to every subsequent command run in that shell.
AgentSecrets solves this through In-Memory Environment Injection via agentsecrets env -- <command>.
The Mental Model: How In-Memory Injection Works
agentsecrets env is an ephemeral process supervisor. It retrieves encrypted secrets from your local operating system keychain, decrypts them in memory, constructs a localized environment block, and spawns the target program directly using the OS execve system call.
Loading diagram...
Under the Hood: The 6-Stage Process Lifecycle
When you execute agentsecrets env -- <command>, the Go runtime executes the following sequence:
1Flag Isolation ()
Standard CLI parsers attempt to parse all incoming flags. If your target command contains flags (e.g. python manage.py runserver --noreload --port 8000), a standard CLI would crash, claiming --noreload is an unknown AgentSecrets flag.
AgentSecrets explicitly sets DisableFlagParsing: true on the command definition:
- The mandatory
--delimiter marks the strict boundary between AgentSecrets options and child program arguments. - The CLI strips
--and forwards all remaining arguments verbatim to the OS executable locator (exec.LookPath).
2Verified Keychain Attestation
Before accessing any secret, the CLI establishes an IPC handshake with the keychain-auth daemon. The daemon verifies the calling binary's cryptographic hash (SHA-256) and PID via kernel-level socket credentials (SO_PEERCRED on Linux, LOCAL_PEERPID on macOS, Named Pipes on Windows). Once attested, the active project's secrets for the selected environment (dev, staging, or prod) are returned to the CLI's memory.
3In-Memory Environment Assembly
The CLI constructs the environment block for the child process:
// cmd/agentsecrets/commands/env.go env := os.Environ() // Inherit host PATH, USER, HOME, etc. for key, value := range secrets { env = append(env, fmt.Sprintf("%s=%s", key, value)) } childCmd.Env = env
- No File System Footprint: The secrets never touch
.env, temporary files, or swap memory. - No Shell Scope Pollution: The variables are bound strictly to the
childCmdprocess descriptor. Your parent terminal shell remains completely unmodified.
4POSIX Signal Supervision (Clean Teardown)
In poorly designed process wrappers, pressing Ctrl+C kills the wrapper and leaves the child process running in the background as an orphaned zombie holding open database connections or network ports.
agentsecrets env runs an active signal supervisor:
// Traps SIGINT and SIGTERM and forwards directly to the child process sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) go func() { select { case sig := <-sigChan: if childCmd.Process != nil { childCmd.Process.Signal(sig) } case <-done: } }()
When you stop a server, web worker, or container, agentsecrets env propagates the interrupt signal directly to the child's PID, allowing frameworks like Django, Node.js, and Celery to execute their graceful shutdown hooks.
5Bidirectional Output Stream Masking ()
Even though credentials reside only in child process RAM, buggy application code, unhandled exceptions, or verbose debug logs might inadvertently print os.environ or error traces to the terminal.
To prevent terminal scrollback and CI log leakage, agentsecrets env wraps the child process os.Stdout and os.Stderr in real-time MaskingWriter streams. The interceptor matches and redacts:
- Plaintext Values:
sk_live_51ABC...->[REDACTED] - Base64 Variants: Encoded strings ->
[REDACTED] - Hex Representations: Hex-encoded bytes ->
[REDACTED] - URL-Percent Escaped: Query parameters ->
[REDACTED]
Output masking is enforced at the kernel pipe layer and cannot be disabled via flags.
6Exit Code Preservation & Audit Recording
When the child command finishes execution:
MaskingWriterflushes any remaining buffered bytes to the terminal.- The exact exit code of the child process (
exitErr.ExitCode()) is extracted and returned. If the child exits with code1or127,agentsecretsexits with code1or127. Makefiles, shell scripts, and CI runners behave as if the child was invoked directly. - An audit event is committed to the local audit trail (
Method: "ENV",AuthStyles: ["env_inject"]). Crucially, only the secret key names are logged, never the values.
The Security Boundary: Guarantees vs. Trade-offs
It is vital to understand the exact security guarantees of Environment Injection compared to the Credential Proxy:
| Security Property | Credential Proxy (call / SDK) | Environment Injection (env --) |
|---|---|---|
| Secrets on Physical Disk | Zero (Never written) | Zero (Never written) |
| Secrets in Shell History | Zero (Never written) | Zero (Never written) |
| Terminal / Log Redaction | Yes (credential_echo defense) | Yes (MaskingWriter stream interceptor) |
| Parent Shell Protection | Immune (Never exported to shell) | Immune (Never exported to parent shell or history) |
| Sibling Process Snooping | Immune (Protected in daemon RAM) | Immune (OS kernel memory boundary isolates child) |
Exfiltration via Shell env | Immune (Key names only) | Neutralized (env, printenv, echo $KEY masked to [REDACTED]) |
| Secrets in Target Address Space | Zero (Application only holds key names) | Localized to Child RAM (Required for DB drivers) |
| Target Compatibility | HTTP/HTTPS APIs only | Universal (Any CLI, database, runtime, container) |
Architectural Rule of Thumb:
- If your application or AI agent makes outbound HTTP calls (OpenAI, Anthropic, Stripe, GitHub), use the Credential Proxy for true zero-exposure security.
- If your application requires direct system variables (Postgres
DATABASE_URL, Redis credentials, Docker Compose, legacy CLIs), useagentsecrets envto eliminate plaintext.envfiles from disk.
Next Steps
- Running Any Process & Real-World Recipes — Step-by-step guides for Docker, Next.js, Django, Celery, and Claude Desktop MCP.
- Proxy vs. Environment Injection — Deep dive into threat models and runtime trade-offs.
- CLI Reference: env command — Complete flag reference and terminal output masking demonstrations.