secretsh 0.2.1

Secure subprocess secret injection for AI agents
Documentation

secretsh

Inject secrets from a .env file into subprocess arguments for AI agents.

CI Crates.io License: MIT

Honest summary: secretsh keeps secrets out of LLM context and shell history, and redacts them from stdout/stderr. It does not protect the .env file, hide secrets from the child process, or redact files the child writes directly. See docs/threat-model.md.

Agent writes:  curl -H 'X-Api-Key: {{NINJA_API_KEY}}' 'https://api.example.com'
Child runs:    curl -H 'X-Api-Key: sk-realkey123' 'https://api.example.com'
Agent sees:    [{"result": "..."}]   ← [REDACTED_NINJA_API_KEY] if leaked in output

Install

# CLI (Rust)
brew tap lthoangg/tap && brew install secretsh
# or: cargo install secretsh

# Python (wraps the CLI binary — install CLI first)
pip install secretsh
# or: uv add secretsh

Pre-built binaries: GitHub Releases.


Quick Start

echo 'NINJA_API_KEY=your-key-here' > .env && chmod 600 .env

secretsh --env .env run --no-shell --quiet -- \
  "curl -sS -H 'X-Api-Key: {{NINJA_API_KEY}}' 'https://api.api-ninjas.com/v2/quoteoftheday'"
import secretsh

result = secretsh.run(
    ".env",
    "curl -sS -H 'X-Api-Key: {{NINJA_API_KEY}}' 'https://api.api-ninjas.com/v2/quoteoftheday'",
    no_shell=True, quiet=True,
)
print(result.stdout)  # [{"quote": "...", "author": "..."}]

Agent Tool (LangChain)

from langchain.tools import tool
import secretsh

@tool
def shell(command: str) -> str:
    """Run a command with secrets from .env. Use {{KEY_NAME}} placeholders.
    Single-quote arguments containing spaces, pipes, $ or &."""
    try:
        result = secretsh.run(".env", command, no_shell=True, quiet=True, timeout=30)
        return result.stdout or result.stderr
    except secretsh.PlaceholderError as e:
        return f"Secret not found: {e}"  # lists available key names
    except secretsh.TokenizationError as e:
        return f"Syntax error: {e}\nHint: wrap | $ & in single quotes."
    except secretsh.CommandError as e:
        return f"Command failed: {e}"

Flags

Flag Default Purpose
--env required Path to the .env file
--no-shell off Block sh/bash/zsh/etc. Recommended for AI agents.
--timeout 300s Kill child after N seconds
--max-output 50 MiB Kill child if stdout exceeds this
--max-stderr 1 MiB Kill child if stderr exceeds this
--quiet off Suppress audit JSON on stderr
--verbose off Show tokenization debug output

Exit Codes

Code Meaning
0 Success
1–125 Child exit code (passthrough)
124 Timeout or output limit exceeded
125 secretsh error (tokenization, placeholder, shell blocked)
126 / 127 Not executable / not found
128+N Killed by signal N

Documentation

Doc Content
docs/cli.md Flags, quoting guide, exit codes
docs/python-api.md secretsh.run() API, quoting guide, exceptions
docs/tokenizer.md Allowed/rejected chars, placeholder syntax
docs/threat-model.md Security model, oracle attacks, limitations
docs/architecture.md Execution pipeline, module map
docs/integrations/ LangChain, PydanticAI, OpenClaw
examples/ LangChain demo, runnable examples

Development

cargo test && cargo clippy -- -D warnings && cargo fmt --check
cd python && PYTHONPATH=. pytest tests/ -v  # 39 Python tests

License

MIT · Contributing · Security