cd /news/developer-tools/show-hn-sandbox-proxy-a-forward-prox… · home topics developer-tools article
[ARTICLE · art-47898] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Show HN: Sandbox-proxy – A forward proxy that injects credentials to sandboxes

A developer released Sandbox-proxy, a zero-dependency Go forward proxy that injects credentials into outbound requests on the wire, allowing sandboxed code to use tokens without seeing them. The tool simplifies secret management for containerized workloads by intercepting HTTPS traffic and injecting credentials only for configured hosts.

read7 min views1 publishedJul 4, 2026
Show HN: Sandbox-proxy – A forward proxy that injects credentials to sandboxes
Image: source

A zero-dependency, stdlib-only Go forward proxy that injects your real credentials (GitHub GH_TOKEN

, npm token, …) into outbound requests on the wire, so code running in a sandbox can use them without ever seeing them.

A simplified version of Infisical's agent-vault, driven by a single script (sandbox.sh

) over a dependency-free proxy binary you own.

Code runs in a container with no network access except through the proxy. The proxy holds your tokens and injects them into outbound requests as they leave — so the workload can use them but never sees them.

sandbox  (git / gh / npm — no token; HTTPS_PROXY, trusts proxy CA)
   │
   │  request without credentials
   ▼
sandbox-proxy  (holds the real token; default-deny allow-list)
   │
   │  + Authorization injected on the wire
   ▼
upstream  (github.com, api.github.com, registry.npmjs.org, …)
  • 🌐 Open by default(allow_all: true

) for easy setup — egress to any host, with credentials injected only on your configured hosts. Setallow_all: false

for strict default-deny (only listed hosts reachable). - 🔏 HTTPS interception via a CA it generates on first run and the sandbox trusts; the intercepted TLS speaksHTTP/1.1 only(ALPN pinshttp/1.1

), and hosts you don't inject into can be blind-tunnelled untouched. - 🛡️ A compromised workload can at most usea token against the hosts you allow — it can't read or exfiltrate the secret itself.

Source the control script once; it gives you a sandbox

function that manages one shared proxy and any number of sandbox containers.

source sandbox.sh

export NPM_TOKEN=npm_xxx           # optional; export any secret your rules need

sandbox proxy up                   # build (if needed) + start the shared proxy
sandbox proxy status               # is it running? on which networks?

cd ~/code/my-app
sandbox run                        # ensures proxy is up, opens a shell in $PWD
sandbox run npm ci
sandbox run git clone https://github.com/you/private.git

Inside a sandbox there is no token in the environment, yet git/npm are authenticated — the proxy injects credentials on the way out. Run as many sandboxes as you like at once; they all share the single proxy:

(cd ~/code/app-a && sandbox run npm test) &
(cd ~/code/app-b && sandbox run npm test) &
sandbox ps                         # list running sandboxes

Commands:

Command Does
sandbox proxy up
Build if needed, start the shared proxy.
sandbox proxy status
Show whether it's running and its networks.
sandbox proxy reload
Restart the proxy, picking up current env/tokens and config edits.
sandbox proxy down / logs
Stop+remove / follow logs.
sandbox run [cmd...]
Ensure the proxy is up, run a sandbox in $PWD (shell if no cmd).
`sandbox build [proxy box
Force-rebuild images.
sandbox ps
List running sandboxes.

🔑 Where secrets come from: for each var in $SANDBOX_SECRET_ENVS

(default GH_TOKEN NPM_TOKEN

), sandbox

uses the environment value if set, otherwise runs SANDBOX_<VAR>_CMD

on the host. GH_TOKEN

defaults to gh auth token

, so just being logged into gh

is enough — no need to export anything. Resolution happens in a subshell at proxy up/reload, so tokens never persist in your shell, and they're passed to the container by name (never on the command line). To pull another secret from a command, e.g.:

export SANDBOX_SECRET_ENVS="GH_TOKEN NPM_TOKEN AWS_TOKEN"
export SANDBOX_AWS_TOKEN_CMD="aws-vault exec me -- printenv AWS_SESSION_TOKEN"

💾 Persisting tool configs / caches: set SANDBOX_VOLUMES

to a whitespace-separated list of docker -v

specs and every sandbox run

mounts them (named volumes are created on first use and survive across sandboxes):

export SANDBOX_VOLUMES="claude-config:/root/.claude codex-config:/root/.codex pi-config:/root/.pi"

Each entry is a raw -v

spec, so host paths ($HOME/.foo:/root/.foo

) and read-only mounts (somevol:/root/.x:ro

) work too. Note these are shared across all sandboxes, so treat anything mounted there as readable by any workload.

♻️ Changing tokens or rules: edit proxy/config.json

and/or update the token source, then sandbox proxy reload

— it re-resolves secrets (picking up a rotated gh

token) and restarts. The CA is stored in a persistent Docker volume, so it survives reloads and sandboxes keep trusting it.

The sandbox network is created --internal

, so a sandbox physically cannot reach the internet except through the proxy. Confirm:

sandbox run sh -c 'env | grep -i token'    # -> nothing (no token inside the sandbox)
sandbox run curl -sI https://example.com   # reachable via the proxy (allow_all default);

Override defaults (network/image/volume names, which env vars are forwarded as secrets) by exporting SANDBOX_*

vars before sourcing — see the top of sandbox.sh

.

📦 Installing packages at runtime: the image sets both upper- and lower-case proxy vars, so apt

, curl

, wget

, go

, npm

, bun

all route through the proxy — apt update && apt install <pkg>

works (needs allow_all

, or the Ubuntu archive hosts allow-listed). These installs live in the --rm

container and vanish on exit; for anything you want every time, add it to sandbox/Dockerfile

and sandbox build box

. Your host TERM

/COLORTERM

are forwarded too, so full-color TUIs work.

proxy/config.json

maps secrets (how to build an auth header, with the value read from the proxy's environment) to rules (which host gets which secret):

{
  "allow_all": true,
  "secrets": {
    "github":     { "type": "basic",  "env": "GH_TOKEN", "username": "x-access-token" },
    "github-api": { "type": "bearer", "env": "GH_TOKEN" },
    "npm":        { "type": "bearer", "env": "NPM_TOKEN" }
  },
  "rules": [
    { "host": "github.com",              "inject": "github" },
    { "host": "api.github.com",          "inject": "github-api" },
    { "host": "*.githubusercontent.com" },
    { "host": "registry.npmjs.org",      "inject": "npm" }
  ]
}

secretstype

isbearer

orbasic

;env

names the host env var holding the token (never the value itself).username

is for basic auth (GitHub uses the token as thepasswordwith any username).rules— matched byhost

, covering all methods and paths. A*.

prefix is a suffix wildcard:*.githubusercontent.com

matchesobjects.

/raw.

/ any subdomain (and the bare domain) — handy for CDN hosts behind gh-release/git-lfs/npm-tarball downloads.inject

names a secret to add on every request; omit it to allow a host with no credential added.—allow_all

for simplicity: egress to any host, with injection still scoped to listed hosts (others are blind-tunnelled, untouched). Set it totrue

by defaultfalse

for strict default-deny — only listed hosts are reachable.⚠️ Withallow_all

on, the proxy is a credentialbroker, not a firewall: a compromised workload can send data anywhere. Flip it tofalse

for untrusted code.

Run sandbox proxy reload

to re-read the config.

The proxy is just a binary — no runtime deps.

cd proxy/src
go build -o sandbox-proxy .                 # or: GOOS=linux GOARCH=amd64 go build ...

GH_TOKEN=ghp_xxx NPM_TOKEN=npm_xxx ./sandbox-proxy   # listens on :3128, writes ca/ca.crt

export HTTPS_PROXY=http://127.0.0.1:3128
curl --cacert ca/ca.crt https://api.github.com/user   # authenticated, token never left the proxy
git -c http.proxy=$HTTPS_PROXY clone https://github.com/your/private.git

Cross-compile for any target with GOOS

/GOARCH

— the output is a single static file you can drop anywhere.

cd proxy/src && go test ./...

Covers the policy engine (host matching, decide

, credential injection incl. placeholder overwrite), config , header/host helpers, WebSocket-upgrade detection, and end-to-end forward-proxy and CONNECT/MITM flows (injection, default-deny, allow_all

) via httptest

. _test.go

files are excluded from the built binary.

Var Default Meaning
PROXY_LISTEN
:3128
listen address
PROXY_CONFIG
config.json
rules file
PROXY_CA_DIR
ca
where ca.crt / ca.key are stored/generated
HTTP(S)_PROXY
upstream proxy for the proxy's own egress (optional)

It lives (modeca.key

stays in the proxy.0600

) in the proxy-only CA volume; sandboxes bind-mountonly the publicca.crt

read-only, never the volume — so a workload can't read the key and mint trusted certs. Keep the CA volume private on the host.Lock down the network, not just the env. The--internal

sandbox network (sandbox-net

) is what actually forces traffic through the proxy; without it a workload could ignoreHTTPS_PROXY

and dial out directly.sandbox.sh

creates it internal by default.Scope tightly. Prefer specific injection hosts over broadallow_all

so a leaked-but-injected token is useful only for what you intended.

── more in #developer-tools 4 stories · sorted by recency
── more on @infisical 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-sandbox-prox…] indexed:0 read:7min 2026-07-04 ·