Skip to main content

Secure subprocess secret injection for AI agents

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

secretsh-0.2.1-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

File details

Details for the file secretsh-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: secretsh-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 7.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for secretsh-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a6cebd7392dc59ed648dacf25f2de6568629fa4b554d72f67f8ec5bfb5679af0
MD5 6d69a2acb40db4da80f1b64c14f91f41
BLAKE2b-256 592fb56bf1c8b9f2589daf1ad4125308eb53004712e84e2baade1cdc2cef1076

See more details on using hashes here.

Provenance

The following attestation bundles were made for secretsh-0.2.1-py3-none-any.whl:

Publisher: publish-pypi.yml on lthoangg/secretsh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page