sproxy (secure proxy)
Motivation
Do not send the secrets (API tokens, passwords) to LLM providers. If the secrets are in the conversation context, you can consider them compromised. So, don't let them ever enter the context. sproxy helps with this.
How it works?
At request time, sproxy detects the secrets placeholders and injects the real secrets to the outbound requests. The LLMs only see the placeholder values at all times.
placeholder {{GITHUB_TOKEN}} real secret
┌────────┐ ───────────────────────► ┌────────┐ ───────────────► ┌──────────┐
│ LLM │ │ sproxy │ leak scan + │ approved │
│ agent │ ◄─────────────────────── │ │ audit │ host │
└────────┘ response └────────┘ └──────────┘
│
├─► ✗ block leak to attacker domain
└─► 🧾 .sproxy/audit.jsonl
Features
- provides a list of placeholder env values to be used by the LLM
- configure specific domains to which the secret should be ingested
- monitor and audit all traffic originating from LLM
- works with authorization Headers, Parameters and Postgres protocol
- local-first and fully open-source
- works with Codex, Claude Code and other harnesses
Prerequisites
sproxy uses mitmdump and will
be pulled automatically by pip install:
pip install sproxy
If you prefer to install mitmproxy separately, use pip install --no-deps sproxy
and make sure mitmdump is available on your PATH (or pass --mitmdump to
sproxy run).
Quickstart
# 1. Write a starter policy and edit it.
sproxy init # creates ./sproxy.toml
# 2. Run your agent behind the guard.
# Start sproxy
sproxy run
# And load the placeholder Env variables
eval $(sproxy env) && codex
# Or run the process together with sproxy
sproxy run -- codex
# 3. After a session, check the audit log wasn't touched.
sproxy audit verify .sproxy/audit.jsonl
On first run, mitmproxy generates its CA at ~/.mitmproxy/mitmproxy-ca-cert.pem.
sproxy points the agent's TLS trust env vars (NODE_EXTRA_CA_CERTS,
REQUESTS_CA_BUNDLE, SSL_CERT_FILE, …) at that file automatically.
Run sproxy ca to print the path.
To observe secret injection on your local machine, follow QUICKSTART.md.
Placeholder environment variables
When a secret name is a valid environment-variable name, sproxy also exports
that name to the guarded process as an per-session secret placedholer
starting with sproxy.
For example, with a GITHUB_API_KEY secret, an SDK sees:
GITHUB_API_KEY=sproxy_v1_<random-session-handle>
sproxy replaces that handle with the real key only for the secret's allowed
hosts. The handle is different for every sproxy run session and stops working
when that session ends.
Secret backends supported:
gopass:PATH,pass:PATH,vault:PATH#FIELD(HashiCorp Vault, via thevaultCLI's existing auth)env:VARfile:PATHliteral:VALUE
Config file
The policy is loaded from -c PATH config file if given, else ./sproxy.toml, else the
user-level ~/.config/sproxy/sproxy.toml.
Relative paths inside a policy (audit_log, sslrootcert, confdir) resolve
against the config file's own directory.
Editing the policy while sproxy run hot-reloads sproxy.
(Note that you might have to re-authorize loading the secrets).
PostgreSQL
The usual placeholder injection does not work for PostgreSQL like it does for http.
SCRAM authentication proves knowledge of the password inside the client,
so there is no request in flight to rewrite.
Instead, each [postgres.NAME] profile becomes a local endpoint that
terminates the wire protocol: the agent's client
authenticates to sproxy with a per-session token.
Sproxy opens the real connection to the host pinned in
policy. The real password never enters the agent's environment,
but it sees a fake placeholder which sproxy uses.
[postgres.develop]
host = "db.example.com" # the real server
port = 5432
listen = 6432 # local endpoint port; omit for auto-assigned
password_source = "gopass:work/postgres/develop/password"
user = "app_readonly" # optional: default role
database = "appdb" # optional: default database
sslmode = "verify-full" # upstream TLS (default); "disable" only for local dev servers
sslrootcert = "" # CA bundle (e.g. the AWS RDS bundle); "" = system trust store
Each endpoint is advertised to the session through an environment variable
named after the profile which will render after sproxy run or sproxy env.
The audit log
Stores one line per request captured. Example:
{"seq":1,"ts":"...","host":"attacker.com","method":"POST","decision":"blocked","rules":["secret:GITHUB_TOKEN"], ...}
TLS interception & certificate pinning
sproxy reads HTTPS by acting as a MITM with a trusted local CA. Clients that
pin certificates (require a specific cert, not merely a valid one) will
reject that CA and fail the handshake, and won't have their secrets replaced.
Use passthrough_hosts to whitelist such hosts:
passthrough_hosts = ["api.vendor.com"] # tunneled without interception
Commands
| Command | What it does |
|---|---|
sproxy run [-c policy] [--port N] [--insecure] [--log-file path] [--no-reload] [-- <cmd…>] |
Run a command behind the guard; no command holds a session open. Policy edits apply live unless --no-reload |
sproxy init [-c path] [--force] |
Write a starter policy |
sproxy env |
Print exports that join this shell to the live session |
sproxy ca [-c policy] |
Print the mitmproxy CA cert path |
sproxy audit verify <log> |
Check the audit chain is intact |
sproxy version |
Print version |
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 sproxy-0.1.1.tar.gz.
File metadata
- Download URL: sproxy-0.1.1.tar.gz
- Upload date:
- Size: 57.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
584d7edde2fd025bed49d6f25b8a3a8bd3adee907e6d3c0b7beff31f4bc6b42f
|
|
| MD5 |
0fc5ff2f888abf45cdb06d52638c90e8
|
|
| BLAKE2b-256 |
e3595d53f783224b660af1e0df7407b3ec378fb3864ffc77d57b8642b366efa4
|
Provenance
The following attestation bundles were made for sproxy-0.1.1.tar.gz:
Publisher:
release.yml on igorpejic/sproxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sproxy-0.1.1.tar.gz -
Subject digest:
584d7edde2fd025bed49d6f25b8a3a8bd3adee907e6d3c0b7beff31f4bc6b42f - Sigstore transparency entry: 2575322556
- Sigstore integration time:
-
Permalink:
igorpejic/sproxy@9c2a681397ce34fc690750906f725998a9cfda4a -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/igorpejic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9c2a681397ce34fc690750906f725998a9cfda4a -
Trigger Event:
release
-
Statement type:
File details
Details for the file sproxy-0.1.1-py3-none-any.whl.
File metadata
- Download URL: sproxy-0.1.1-py3-none-any.whl
- Upload date:
- Size: 44.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f343eb380d203acb4b86d151ef1ad060e4f6bcc8b3e28095f11c197f37a4b87d
|
|
| MD5 |
29016ff568b97640ffb0d983cdff6b4e
|
|
| BLAKE2b-256 |
a6ce630353c7c61a7dab3cc74ac2c5faadc399917105c6821a8b7aade161cf48
|
Provenance
The following attestation bundles were made for sproxy-0.1.1-py3-none-any.whl:
Publisher:
release.yml on igorpejic/sproxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sproxy-0.1.1-py3-none-any.whl -
Subject digest:
f343eb380d203acb4b86d151ef1ad060e4f6bcc8b3e28095f11c197f37a4b87d - Sigstore transparency entry: 2575322659
- Sigstore integration time:
-
Permalink:
igorpejic/sproxy@9c2a681397ce34fc690750906f725998a9cfda4a -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/igorpejic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9c2a681397ce34fc690750906f725998a9cfda4a -
Trigger Event:
release
-
Statement type: