Skip to main content

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 the vault CLI's existing auth)
  • env:VAR
  • file:PATH
  • literal: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

sproxy-0.1.1.tar.gz (57.9 kB view details)

Uploaded Source

Built Distribution

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

sproxy-0.1.1-py3-none-any.whl (44.8 kB view details)

Uploaded Python 3

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

Hashes for sproxy-0.1.1.tar.gz
Algorithm Hash digest
SHA256 584d7edde2fd025bed49d6f25b8a3a8bd3adee907e6d3c0b7beff31f4bc6b42f
MD5 0fc5ff2f888abf45cdb06d52638c90e8
BLAKE2b-256 e3595d53f783224b660af1e0df7407b3ec378fb3864ffc77d57b8642b366efa4

See more details on using hashes here.

Provenance

The following attestation bundles were made for sproxy-0.1.1.tar.gz:

Publisher: release.yml on igorpejic/sproxy

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

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

Hashes for sproxy-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f343eb380d203acb4b86d151ef1ad060e4f6bcc8b3e28095f11c197f37a4b87d
MD5 29016ff568b97640ffb0d983cdff6b4e
BLAKE2b-256 a6ce630353c7c61a7dab3cc74ac2c5faadc399917105c6821a8b7aade161cf48

See more details on using hashes here.

Provenance

The following attestation bundles were made for sproxy-0.1.1-py3-none-any.whl:

Publisher: release.yml on igorpejic/sproxy

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

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

Supported by

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