Skip to main content
ironrun sits between your AI agent and the shell, creating an airgap that secrets can cross in only one direction. When an agent asks to run a command, ironrun resolves credentials from your secret provider, injects them into the child process environment, streams the output through a redactor, and hands back a clean result — exit code, duration, and stdout/stderr — with every secret value replaced by [REDACTED]. The agent gets the information it needs to continue working; it never gets the credentials themselves.

The threat model: what happens without ironrun

Coding agents run shell commands on your machine. Most of the time that’s fine. The problem is the small set of commands that print the environment:
When an agent runs one of these — often while legitimately debugging something you asked it to fix — the secret value lands in the chat transcript. But there’s a second exposure vector you may not have noticed yet. When Claude Code runs a command that uses a secret, that command invocation is logged verbatim to:
These JSONL files are Claude Code’s conversation history. They contain every tool call, every shell command, and every piece of output — including any secret values that appeared in that output. They persist between sessions and across project restarts, and they are readable by any process with access to your home directory. ironrun redacts secret values from command output before it reaches the agent, so values never enter the conversation and never end up in these logs.

The MCP layer: how a sealed run works

When ironrun runs as an MCP server (ironrun mcp), it exposes a run_sealed tool to the agent. Here is the complete sequence for a single command:
The MCP server exposes these value-blind tools to the agent:
  • list_commands — returns command names and their argv, nothing else
  • run_sealed — runs a policy command by command_id or runs arbitrary argv inside a human-trusted workspace session; returns exit code, duration, and redacted stdout/stderr
  • request_workspace_access and workspace_status — requests temporary project/environment access and inspects safe session metadata
  • validate_policy — confirms the policy is well-formed and returns provider and command count
  • propose_command — stages a new command for human approval; does not execute anything
None of these tools have a return path for secret values.

Output redaction

ironrun’s redactor processes all stdout and stderr before they reach the agent. It covers:
  • Literal values — the exact string of each secret
  • Base64-encoded forms — the base64 encoding of each secret value
  • Hex-encoded forms — the hex encoding of each secret value
  • URL-encoded forms — percent-encoded forms of each secret value
  • Entropy scan — a warn-only pass that flags high-entropy tokens that look like secrets but weren’t registered values; the agent sees a note counting these, never the token itself
If output is truncated at the max_bytes limit, ironrun notes that in the result. If the entropy scan fires, the agent sees [ironrun] note: N high-entropy token(s) in the output may be an unredacted secret — a count, never the token.

Security hardening

Both of these hardening features are on by default and fail open: if the kernel or OS does not support them, ironrun logs a warning and continues rather than blocking execution.
Seccomp syscall filter (Linux) — on Linux, every command runs under a seccomp denylist that blocks ptrace, process_vm_readv, and similar memory-snooping syscalls. This prevents a child process from reading secrets out of the ironrun process’s own memory. You can turn it off per command with seccomp: false, policy-wide with seccomp_default: false, or globally with the environment variable IRONRUN_SECCOMP=off. No-network option — set no_network: true on any command to block outbound network access for that command’s child process (Linux network namespace; macOS sandbox-exec). This is useful for test commands that should never phone home.

What ironrun does NOT protect against

ironrun guards the path between the agent and the command output. It is not a sandbox for hostile code. Be honest with yourself about these limits:
  • A command that deliberately writes a secret to a file and reads it back later will succeed.
  • Network exfiltration by a command running with no_network: false (the default) is not blocked. A trusted agent could deliberately exfiltrate a secret through a network request inside a trusted command.
  • Secrets in files that the command itself creates are not automatically cleaned up.
  • Anyone who already has access to the machine ironrun runs on can read secrets through other paths.
ironrun protects agent context, logs, and routine output. It is not an OS-level sandbox for a process you choose to trust. See the project’s SECURITY.md for the full threat model.

Audit log

Every run_sealed call appends a tamper-evident, hash-chained record to the audit log. The record includes the command, argv, and secret names — never values. The log lives at $XDG_STATE_HOME/ironrun/audit.log by default.
You can redirect or disable the log with the IRONRUN_AUDIT_LOG environment variable or the top-level audit_log: field in ironrun.yml:

Performance

ironrun adds approximately 5–10ms overhead per command invocation:
  • ~2ms for provider lookup with env or envfile providers
  • Up to ~100ms for a 1Password CLI call (network + auth)
  • Under 1ms for the redaction layer on typical output sizes
The overhead is in secret resolution, not in the execution path itself.