Security & privacy
contextzip reads your project and writes a ZIP that you choose to upload. It never uploads anything itself, and it works hard to keep secrets out of that ZIP.
How secrets are handled
Three layers, from strictest to opt-in:
01
Excluded by default
Secret files are left out of every run, including --git-changes. Including a folder doesn't bring back the secrets inside it.
02
Redacted when you ask
Name a secret file on purpose — include .env, always_include, the config UI — and its values are redacted, every time.
03
Scanned if you want
limits.redact_secrets scans every included text file for hardcoded keys and tokens, and masks them in the ZIP copy.
| Secret files | Patterns |
|---|---|
| Environment files | .env .env.* |
| Private keys & keystores | *.pem *.key *.p12 *.pfx *.jks *.keystore *.ppk id_rsa id_ed25519 … |
| Tool credentials | .npmrc .netrc .pypirc .pgpass .dockercfg .docker/config.json |
| Cloud credentials | .aws/credentials *serviceaccount*.json *credentials*.json kubeconfig |
| Infrastructure state | *.tfstate .terraform/ |
Redaction
Want the AI to see which environment variables your app expects? Include your .env — with contextzip include .env or always_include. Keys, comments and layout stay; every value becomes [REDACTED]. Drag to compare:
# DatabaseDATABASE_URL=[REDACTED]export STRIPE_KEY="[REDACTED]" # billingSESSION_SECRET=[REDACTED] PORT=[REDACTED]DEBUG=
- Every value is redacted, even harmless ones like
PORT— guessing which values are safe is exactly how leaks happen. - Other secret files you include get a pattern scan for private-key blocks, API keys and tokens.
- A secret file that isn't text (a .p12, say) can't be redacted, so it's left out and listed in the report.
- With
limits.redact_secrets: true, ordinary files are scanned too — AWS, Google, GitHub, Slack, Stripe, Anthropic and OpenAI keys, JWTs, private-key blocks andpassword = "…"-style assignments. - Your files on disk are never modified. The report lists everything that was redacted.
Redaction is best-effort
It recognises known formats, not every possible secret. Before uploading from a sensitive project, runcontextzip --dry-run --verbose and read the report.Network access
Packaging, apply-zip, watch and the config UI work entirely offline. Two features use the network, only when you run them:
| Feature | What is sent | To |
|---|---|---|
| --prompt | Your prompt, the detected stack, and paths + sizes of already-filtered files. Never contents. | Google Gemini API |
| update | A request for the latest version number | PyPI |
There is no telemetry, analytics or background check-in.
Local by design
- Files outside the project are never included; dangling or looping symlinks are skipped.
- apply-zip manifests stay next to the ZIP on your machine — never inside it.
- apply-zip removes a file only with your explicit OK, never one you've changed since the snapshot, and asks before overwriting your own edits.
- Snapshots of what you sent stay in .contextzip/snapshots/ on your machine — gitignored and pruned automatically.
- The config UI binds to 127.0.0.1, requires a one-time token and shuts itself down.
- Your Gemini key lives in your personal config, never in the project.
Reporting a vulnerability
Please don't open a public issue. Email akadeepesh@gmail.com with the details and steps to reproduce — you'll hear back within 48 hours. The full policy is in SECURITY.md.