See what your AI tools actually send
When you press Tab in Cursor or paste into Claude, the assumption is “just my prompt goes out.” The reality is messier. upbox is a local proxy and dashboard that records every request your AI assistants make, redacts secrets before forwarding, and keeps a tamper-evident audit log of what happened: on your machine, with zero cloud calls.
A day in the life of one developer.
illustrative figures · your real numbers appear in the dashboard · single workstation
“Just my prompt goes out.” Not really.
Vendors aren't necessarily being shady. Their docs just don't match what people think is happening, and there's no built-in way to verify from the outside. So we built one.
- 01The current file. Often neighbor files too.Tab-complete in Cursor frequently ships several KB of surrounding context, including files you didn't have open.
- 02The project tree, env vars, sometimes shell history.Workspace metadata gets bundled in. None of it is logged anywhere you can read.
- 03Secrets from .env files you never meant to share.An AWS_ACCESS_KEY sitting two lines above the function you're editing goes out by default.
- 044–8 AI tools running at once.A typical developer can't track all of it. Nobody can.
The dashboard, running locally.
Every request, in real time, grouped by tool. Click any row to inspect the body, headers, redactions, and what was forwarded.
Request body (100 KB excerpt)
{
"model": "gpt-4o-cursor",
"stream": true,
"messages": [
{ "role": "system", "content": "You are a coding assistant." },
{ "role": "user", "content": "Fix the type error in this file." }
],
"context": {
"file": "src/payments.ts",
"neighbors": ["lib/utils.ts", "types.d.ts"],
"snippet": "const STRIPE_KEY = 'sk_live_3Hf9...XQpZ';\n const AWS_ACCESS = 'AKIAXXXXXXXXXXXXXXXX';"
},
"metadata": { "endpoint": "cmd-k", "workspace": "monorepo" }
}Six capabilities. One binary. One SQLite file.
One file per platform. On Windows, double-click and it runs.
Every release ships one-file executables for Windows, macOS (Apple Silicon) and Linux, built and smoke-tested on GitHub's runners, with a .sha256 beside each. Double-click upbox.exe and it asks for administrator rights, asks once before installing the local CA, starts, and opens the dashboard in your browser. Unsigned for now; pipx stays the path for Intel Macs and other architectures.
Live feed, curated capture
Every request as it happens, grouped by tool. 15 bundled fingerprints: Cursor, Claude, Claude Code, Copilot, ChatGPT, Windsurf, Codeium, Continue, Cody, Perplexity, Tabnine, Replit, plus generic OpenAI / Anthropic / Gemini fallbacks. upbox start redirects only a curated list of AI-tool processes; VPN clients (Tailscale, WireGuard, OpenVPN, NordVPN, Mullvad, ProtonVPN) and unrelated apps are never touched, so tunnels stay up. Override with --capture-spec "claude,cursor" or --capture-all.
Bodies, headers, the lot
The actual prompt. The actual file content. The actual headers, with credential values replaced by markers. JSON, NDJSON, and SSE bodies formatted and captured up to 100 KB. Content-Type-aware: parses JSON properly so gzipped or nested-field secrets don't slip through. Or store no bodies at all: capture.yaml keeps metadata only.
Strip secrets before forwarding
Regex rules strip .env blocks, API keys, and PII patterns before the request reaches the cloud. Ships with AWS / OpenAI / Anthropic / Google / Slack / GitHub defaults, live-reloaded when you edit them. Auth headers and URL keys are never written to the audit log.
Domain allowlist per tool
Allow only the destinations you've sanctioned. An off-allowlist host is either flagged (warn: forwarded, but recorded) or blocked (HTTP 403, never leaves the machine). A TLS allowlist (built from tools.yaml) means non-AI HTTPS traffic passes as a CONNECT tunnel without decryption, so Teams and pinned-cert apps keep working. Banking, health, webmail, government, and identity providers are never decrypted at all, even under --capture-all.
Evidence and subject rights
SHA-256 hash chain over every row, upbox verify to check it, upbox checkpoint to seal it. Export as upbox.audit.v1, JSONL, or CSV, filtered by tool and time range. capture.yaml can stop at metadata, upbox erase removes records as chain-preserving tombstones (GDPR Art. 17), and upbox report writes what upbox holds about you (Art. 15).
Nothing leaves your machine
SQLite on disk. Dashboard binds to 127.0.0.1 only and refuses to start on any other host. Zero outbound calls from upbox itself. Owner-only file permissions, and upbox doctor tells you whether the disk underneath is encrypted.
Supervisor. Two children. Boring stack.
upbox start supervises two child processes: the proxy and the dashboard. They never talk directly. They share state through SQLite in WAL mode: the proxy writes audit rows, the dashboard reads them. SQLite WAL is the IPC. mitmproxy is the proxy core. FastAPI + Jinja2 for the dashboard: server-rendered partials, a little vanilla JS, no build step.
- → mitmproxy · MIT · proxy core
- → FastAPI · MIT · dashboard backend
- → Jinja2 · BSD-3 · server-rendered templates
- → SQLite · public domain · audit log
- → Typer · MIT · CLI framework
curated AI processes (VPN clients, banking, OS noise: Claude · Cursor · ChatGPT never redirected · tunnels stay up) Codex · Ollama · code · browsers │ ▼ LocalMode redirector · mitmproxy-rs · OS-level capture ┌─────────────────────────────────┐ │ mitmproxy core + upbox addons │ ─ AI host (allowlist) ─▶ decrypt · process · forward │ ┌───────────────────────────┐ │ to cloud LLM │ │ 1 fingerprint (tag tool) │ │ │ │ 2 enforce (allow|warn|403)│ │ ─ pinned host (off list) ─▶ CONNECT tunnel │ │ 3 redact (json-aware) │ │ (no decryption · │ │ 4 capture → SQLite │ │ Teams · banking │ └───────────────────────────┘ │ keep working) └────────────────┬────────────────┘ ▼ ┌──────────────────┐ ┌──────────────────┐ │ SQLite · WAL │ ◀────┤ dashboard │ │ ~/.upbox/ │ │ FastAPI + Jinja2 │ └──────────────────┘ └──────┬───────────┘ │ ▼ 127.0.0.1:8800 ← you ✗ refuses any other host
Six ways. Same upbox.
Pick whichever fits your setup. The download needs nothing; the package installs need Python 3.12+.
The deadline moved. The evidence still has to hold.
On 24 July 2026, Regulation (EU) 2026/1744 deferred the AI Act's high-risk deployer obligations, Article 26 among them, to 2 December 2027 and 2 August 2028. Article 50 transparency applies since 2 August 2026, and GDPR always did. upbox is a deployer-side tool: it does not certify you compliant, it produces evidence and controls that hold up.
- Content-aware: JSON bodies parsed, walked, and re-serialised
- Defaults: AWS / OpenAI / Anthropic / Google / Slack / GitHub keys and dotenv lines
- Credentials in headers and URL query strings are never written to the audit log
- capture.yaml with bodies: false and headers: false stores metadata only
- Two-tier retention in retention.yaml: body_days (default 7) clears bodies and headers, record_days deletes rows and records the gap in the chain
- upbox report -o report.md --records records.ndjson: the hand-over document plus the machine-readable copy
- The dashboard shows the same live at /transparency
- The controller's identity is yours to fill in; the report says so rather than guessing
- upbox erase --id N --reason "...", or by host, tool, or time range, with --dry-run
- The row becomes a tombstone: only the timestamp and chain hashes survive; every content column and digest is cleared
- Disclosed, not hidden: upbox verify, every export, and the report count erasures and carry the reason
- A legal hold refuses erasure until released (Art. 17(3)(e), data needed for legal claims)
- upbox export --format csv for the register, --format audit for evidence
- Every row names the tool, the host, the size, and the outcome
- Local CA the user installs and can uninstall (upbox init --uninstall)
- Dashboard binds 127.0.0.1 only; zero outbound calls from upbox itself
- Tamper-evident SHA-256 hash chain: upbox verify recomputes it, upbox checkpoint seals the head
- Owner-only file permissions; upbox doctor reports whether the volume is encrypted. No in-app encryption, by design
- Per-tool destinations, data classes, and observed volume from the audit log
- The audit export states its own coverage: what was intercepted and what passed through undecrypted
- Never-decrypt list on by default: banking, health, private webmail, government, identity providers (no_intercept.yaml), even under --capture-all
- Metadata-only capture is the recommended configuration on machines you do not own
- Bodies cleared after 7 days by default; per-record legal hold when something must be kept
- Read the Article 88 section of docs/ai-act-mapping.md before deploying on machines you do not own
- What was sent, when, where, by which tool, in what size, with what status. Queryable per tool, exportable.
- Live dashboard groups traffic by tool, host, request size
- Audit log queryable and exportable per tool and time window
- ts · tool · method · scheme · host · path · req_bytes · resp_bytes · status
- body_hash · headers_sha256 · body_excerpt_sha256 · entry_hash: integrity that survives retention
- redactions_applied_json · enforcement: what the engine intervened on, and whether the request was forwarded
- upbox export --format audit: versioned NDJSON with ruleset digests, the chain verification result, and a coverage statement
- upbox export --format jsonl|csv|audit with --since / --until / --tool filters
- Auditable open-source proxy + redaction + enforcement + retention
- Exportable evidence trail rather than verbal policy claims
upbox is not legal advice. It is a deployer-side technical measure: it produces evidence and controls, not a certification. Consult counsel for compliance sign-off. The article-by-article pages linked in the table render the Act as published in 2024 and do not yet reflect the 2026 Omnibus amendments; check dates against EUR-Lex and the official implementation timeline.
Questions you should be asking.
A closed-source tool that watches your AI traffic is itself a privacy problem. The auditor has to be open.
No. upbox makes zero outbound network calls of its own. The proxy forwards the requests your AI tools were going to make anyway: that's the entire network footprint. The dashboard binds to 127.0.0.1 only and refuses to start on any other host.
Not since v0.4.0. Each release ships one-file executables for Windows x86_64, macOS Apple Silicon, and Linux x86_64 (glibc 2.35 or newer), built by PyInstaller on GitHub's runners and smoke-tested on each platform before upload. They bundle Python and mitmproxy. They are unsigned, so macOS needs xattr -d com.apple.quarantine and Windows shows SmartScreen once; a .sha256 sits beside every file. Intel Macs and other architectures use pipx install upbox-sh, which needs Python 3.12 or newer.
Stored locally in ~/.upbox/upbox.db (SQLite, WAL mode, owner-only permissions). The body_excerptcolumn holds up to the first 100 KB of each body; when a body is larger, the dashboard shows a “first 100 KB of N” notice rather than silently cutting it. body_hash (SHA-256 of the full body) and req_bytes (true size) are always recorded, so a truncated excerpt is still provable. Auth headers and credentials in URL query strings are replaced with markers before anything is written. By default, retention clears stored bodies and headers after 7 days while the row and the hash chain stay intact. Or store no bodies at all: see the next question.
Yes. ~/.upbox/rules/capture.yaml has two switches, bodies and headers. With both false, upbox keeps timestamps, tools, hosts, paths with credentials removed, sizes, status codes, the SHA-256 of each body, and the redaction and allowlist outcomes, and nothing a prompt contained. Redaction still runs on the way out. The setting is live-reloaded, editable on the dashboard settings page, and recorded in every audit export. A file that fails to parse puts upbox in metadata-only mode rather than storing more than you meant. It is the recommended configuration on machines you do not own.
It scales with how large the captured bodies are and how long you keep them. Retention is configured in ~/.upbox/rules/retention.yaml: body_days (default 7) clears bodies and headers but keeps the row, and record_days (default: never) deletes whole rows and records the gap in the chain so upbox verify reports a disclosed deletion rather than tampering. upbox prune --dry-run shows what a pass would remove; upbox hold exempts a range. With the defaults, the database stays small: once bodies are cleared, a row is roughly a kilobyte of metadata and hashes.
Yes, since v0.2.0. Every row carries a SHA-256 over its own fields plus the previous row's hash. upbox verify recomputes the chain and reports edited content, deleted rows, inserted or reordered rows, and a botched restore. What it cannot do: the algorithm is public and keyless, so anyone with write access to the file could recompute a consistent chain or truncate the tail. The chain is worth something once a head hash has left the machine, which is what upbox checkpoint is for: seal the head, then mail it, commit it, or have it timestamped. upbox will not anchor it for you, because it makes no outbound calls. Erasures on request are disclosed, not hidden: a tombstone keeps its position and hash, and verify counts it.
Yes. upbox erase --id N --reason "..." (or --host, --tool, --since, --until) erases individual records for GDPR Article 17. The row becomes a tombstone: tool, host, path, sizes, headers, body, and hashes of the content are cleared, and only the timestamp and the chain hashes stay, so upbox verify still passes and reports the erasure with its reason. Preview with --dry-run. A row under legal hold refuses the whole operation until you release the hold.
upbox report -o report.md --records records.ndjson. The Markdown says what upbox holds about this machine's user: the categories of data and whether each is stored, recipients per tool and host, the retention policy in force, any erasures, chain status, and how to get a copy or erase. The NDJSON is the machine-readable copy of the records. The dashboard shows the same at /transparency. The controller's identity is yours to fill in; upbox says so rather than guessing.
Not by upbox, on purpose. It runs as an unattended daemon, so any in-app key would sit next to the database and defeat strings upbox.db and nothing else. upbox sets ~/.upbox to 0700 and the database to 0600, and leaves encryption to the volume: FileVault, BitLocker, or LUKS, with keys in a TPM or Secure Enclave. upbox doctor reports whether that is on, along with file modes and chain health. The stronger control is not storing the data in the first place: metadata-only capture, redaction, and retention.
Negligible. The mitmproxy core handles tens of thousands of requests per second; AI tools peak in the low hundreds per hour. Latency added per request: ~1–5 ms.
A handful of mobile and certain desktop clients ship with hard-coded CA fingerprints. Without modifying the app binary, you can't MITM them. Known-working and known-broken tools are listed in the docs. Banking, health, webmail, government, and identity-provider destinations are deliberately never decrypted at all, whatever else you configure.
Yes. Edit ~/.upbox/rules/tools.yaml (or redact.yaml, allowlist.yaml, capture.yaml), or use the dashboard's /settings page. The running proxy picks up the change within about two seconds, no restart. A broken edit keeps the previous rules loaded. Adding a brand-new intercepted host still needs a restart, since the TLS scope is fixed at boot.
Technically yes. Legally, intercepting TLS on an employee device is employee monitoring, and GDPR Article 88 leaves the rules largely to national law; in Italy it needs a union agreement or Labour Inspectorate authorisation. Inform workers and their representatives first, run metadata-only capture, keep the default never-decrypt list, and read the Article 88 section of the AI Act mapping doc. Running upbox on your own machine raises none of this.
Install once. Run it for a week. The first screenshot is usually a surprise.
v0.4.1 just shipped: one-file binaries for Windows, macOS and Linux, no Python needed, on top of metadata-only capture, erasure, and the transparency report. The fastest way to help: install it, run it against your daily tools, and report what surprised you.