Secure subprocess secret injection for AI agents
Project description
secretsh
Inject secrets from a .env file into subprocess arguments for AI agents.
Honest summary: secretsh keeps secrets out of LLM context and shell history, and redacts them from stdout/stderr. It does not protect the
.envfile, 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6cebd7392dc59ed648dacf25f2de6568629fa4b554d72f67f8ec5bfb5679af0
|
|
| MD5 |
6d69a2acb40db4da80f1b64c14f91f41
|
|
| BLAKE2b-256 |
592fb56bf1c8b9f2589daf1ad4125308eb53004712e84e2baade1cdc2cef1076
|
Provenance
The following attestation bundles were made for secretsh-0.2.1-py3-none-any.whl:
Publisher:
publish-pypi.yml on lthoangg/secretsh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
secretsh-0.2.1-py3-none-any.whl -
Subject digest:
a6cebd7392dc59ed648dacf25f2de6568629fa4b554d72f67f8ec5bfb5679af0 - Sigstore transparency entry: 1329833687
- Sigstore integration time:
-
Permalink:
lthoangg/secretsh@676788f927a6e1f6bb13a0ec2dec1c4a4c27996d -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/lthoangg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@676788f927a6e1f6bb13a0ec2dec1c4a4c27996d -
Trigger Event:
release
-
Statement type: