AI coding agents are now part of a lot of security work. They are good at the parts a tester has no time for: going through every request, every parameter and every file rather than a sample of each. But none of that work happens on your machine. Everything the agent reads is sent to a model running on someone else's servers. So are you sending your client's data to an AI provider?
The usual advice lands in one of two places: run a local model, or don't paste client data. Both work. Both cost you the thing you wanted. A 7B model on a laptop is not the model that spots the subtle chain across three hosts, and an agent you feed carefully redacted scraps by hand is an agent you are babysitting instead of using.
There is a third option. Almost none of that data needs to be there in the first place: the model does not need the real hostname to reason about a finding on it. It needs a hostname that stays the same every time it sees it.
That is where redactproxy(https://github.com/CSPF-Founder/redactproxy) comes in.
Before we get to what redactproxy does, we need to understand where the work actually happens. Claude Code is the part on your machine: a terminal tool that reads your files, runs your commands and collects the output. The model is not on your machine at all: it runs on an AI provider's servers, Anthropic for example. Claude Code does no reasoning of its own, so anything it needs an answer about, including the scan output and the config file it just read, is sent to those servers over the API.
RedactProxy
redactproxy is an open-source tool from the Cyber Security & Privacy Foundation. It sits between Claude Code and the provider, on your own machine, and rewrites that API traffic in both directions. On the way out it replaces real client values with stable fake ones. On the way back it puts the real ones in again, before Claude Code ever sees the response.
The provider only ever sees placeholders. Your tool calls still run against real infrastructure, because the substitution back happens before the response reaches the agent. When the model writes a
Bash command against a placeholder hostname, Claude Code receives the real hostname and runs it against the real host. Not just the first time: on every response, ten turns later, for the life of the conversation.The swap happens inside the traffic itself, so nothing about the way your team works changes. No telemetry, no sync, no backup: everything it stores stays on the machine you run it on.
What the model receives
Here is some scan and config-dump output, exactly as Claude Code would send it, next to what the model actually receives.
- The
mail.subdomain survives, and the same organisation placeholder appears in both the hostname and the email address. The relationship between them is intact. - The host octet
.19survives. Only the /24 network changed, so hosts that were adjacent stay adjacent. - The AWS key still looks like an AWS key, so the model knows what kind of secret it found without seeing the secret.
- The connection string collapses into one opaque placeholder, because the whole credential span is sensitive.
- The
nginxbanner, the latency, the port, the Dell OUI comment: untouched. None of them identify the client.
An engagement is redactproxy's word for one client project. Inside one, the same real value always gets the same fake. The hostname that became
tok5198ede8bdbb1ada.internal this morning is still that same fake tomorrow, and in every request in between. This is not a convenience. It is the reason the tool is usable at all.The model can still work out that two hosts belong to the same organisation. It just never learns which organisation.Because
tok1a2b3c4d5e6f7890.com and mail.tok1a2b3c4d5e6f7890.com are consistently the same fake, the model can reason that a finding on one host relates to a finding on another, that an email address belongs to the same company as a web server, that the same credential turned up in two places. All the analytical work survives. The identity does not.The mappings live in the engagement's own folder and survive restarts, so the placeholder the model saw yesterday is still the same one today. Each engagement is self-contained and shares nothing with the others.
Redaction that destroys structure destroys usefulness. Where a value's shape carries something useful but not identifying, the shape is kept:
FAKE in a position where a real key can only hold a digit or a letter A to F, so no vendor could ever issue one.Detection is regex plus a validation step. No model in the loop, no network call, no learning. The detector set covers, roughly:
- Network identity: domains and hostnames (bare or inside URLs), IPv4, IPv6, MAC addresses.
- People: email addresses, NANP and international phone numbers.
- Credentials for 25+ vendors: AWS, GitHub, GitLab, Slack, Stripe, Razorpay, Google, npm, DigitalOcean, Cloudflare, Azure, Docker Hub, CircleCI, Terraform, Snyk, Vault, Twilio, SendGrid, OpenAI, Anthropic and more, plus JWTs, bearer tokens, connection strings, PEM private keys and password hashes.
- Regional PII: Indian Aadhaar and PAN numbers.
- AD artifacts: machine account names, GPP
cpasswordvalues. - Client identity: whatever you add by hand, which is the part that matters most. See below.
burpcollaborator.net, interact.sh, webhook.site) are never the client's, and common CDN and public dev platform hostnames say nothing about who the client is. Every category can be switched off per engagement.Only the parts of a request that carry content get scanned, and only the values that match get replaced. Everything else is left exactly as it was. MCP tool calls and results are scanned too, because an MCP server is local infrastructure producing exactly the client data this exists to keep in.
Fail closed
If the proxy cannot finish redacting a request, it returns an error instead of sending it on. A malformed request, a detector that errors, a store that cannot save a new mapping: all of them fail the request rather than let it through.
An unredacted forward is the one outcome this project treats as worse than a broken request.
Setting up an engagement
go install github.com/CSPF-Founder/redactproxy/cmd/redactproxy@latestThen, in a folder for the engagement. Name it after an engagement code, not the client; the Known gaps section explains why that matters more than it looks.
cd ~/engagements/eng-2026-014 redactproxy wizard --engagement eng-2026-014The wizard asks four things. First, customer name variations: the legal name, the trading name, abbreviations, product names, internal codenames. No detector can match a name, so this is the only way they get redacted. They become case-insensitive substring matches, so
XYZCorp also catches XYZCorporation.Second, domains. Give the base domain only. Subdomains, email addresses at that domain and URLs all resolve from it automatically. Internal-only names work too: an AD forest, or any private scheme that will never appear on a public suffix list.
Third, which API this engagement talks to. Real Claude by default. redactproxy never asks for an Anthropic credential; it forwards Claude Code's own authentication untouched. Anything else speaking the Anthropic Messages API works too, z.ai for example, and each engagement remembers its own choice, so two client projects can run against different providers side by side.
Fourth, it offers two conveniences for the folder: a
CLAUDE.md note explaining the placeholder shapes, and a .claude/settings.local.json that points Claude Code at the proxy and closes several channels that bypass the proxy entirely.Then:
redactproxy # terminal 1 claude # terminal 2, already pointed at the proxyThat terminal running the proxy is also a live console. Type
show to see every mapping minted so far, remove <value> to drop a bad one, or rules block "XyzExample" to add a value mid-session without interrupting anything.The
CLAUDE.md note is not decoration. Without it, a session sees strange placeholder values with no explanation: it corrects them as typos, hesitates to use them in tool calls, or retypes them from memory slightly wrong. The note tells the model these are stable identifiers to copy verbatim. It also covers a trap worth knowing yourself: if the model decodes base64 inline, the decoded content lands in its own output completely unprotected, because the encoded form passed through unredacted. Decoding to a file with Bash and reading the file back gives that content a normal pass through redaction.The settings hardening closes paths that never touch
ANTHROPIC_BASE_URL at all. The Artifact tool is a confirmed leak path: a report published through it goes straight to a hosted claude.ai URL, entirely unredacted, through a separate service call the proxy never sees. The wizard removes it from the session entirely rather than prompting for it each time, because a permission prompt can be approved out of habit and a tool that was never offered cannot leak anything. It also turns off WebFetch's safety check, which sends the target hostname to Anthropic before the fetch, whichever provider the engagement uses. A domain being reconned is exactly the value this tool exists to keep off side channels.Known gaps
redactproxy ships a Known gaps page, and it is worth reading before you point this at real client data. The ones that matter most:
- Your folder name is the big one, and redaction cannot fix it. Claude Code puts its working directory into the
systemfield of every request, and that field is deliberately never scanned. A folder calledxyz-example-bank-pentestsends "xyz example bank" to the model on every single request no matter what your rules say. The tool warns about it, at wizard time and at startup, but the only fix is to name engagement folders after an engagement code. - Encoded data passes straight through. A
.envpiped throughbase64, anxxddump, Terraform state: none of it looks like anything to a regex. Decode locally first. - Names and prose are not detected. This is what
rules blockis for, and why it is the wizard's first question. A company name shows up in URL paths, ticket references, code comments and commit messages, and no detector can recognise it.
Who this is for
Pentest and consulting teams who want the productivity of an AI coding agent on a live engagement, and who would rather not explain to a client why their internal hostnames are in a third party's logs.
It was built for pentest work, and that shapes the vocabulary: engagements, clients, findings. Nothing in the redaction is specific to offensive work, though. Blue teams and infrastructure teams hit the same problem: a SOC analyst pasting alerts full of internal hostnames, a sysadmin debugging a manifest with credentials in it, anyone under an NDA who wants an AI agent working on real data. The detectors only care about the shapes they recognise, not why you are looking at them.


