Skip to content
Table of contents7 sections · tap to jump
  1. The Test Bench: How to Capture the Traffic
  2. What Fires on Keypress: Mapping the Transmission Triggers
  3. 'Local Mode' Under the Microscope: Do Air-Gap Claims Hold?
  4. Reading the Fine Print vs. Reading the Packets: Where Terms and Reality Diverge
  5. The High-Value Targets: Code That Carries the Most Exposure
  6. Your Egress Playbook: Practical Controls You Can Apply Now
  7. What We Still Can't See: Honest Gaps
A wooden desk with a monitor, mechanical keyboard, copper task lamp, coffee mug, and open notebook under warm lighting

ArticlesecurityDeep read

The Real Privacy Audit: What Data Your AI Coding Assistant Sends Home

Ahmad JAug 5, 202611 minUpdated Sep 14, 2026

Stop trusting privacy policies. Put your AI coding assistant behind a proxy and watch exactly what your code transmits: what fires on every keystroke, what "local mode" really hides, and how to shut the channel.

A deep read: the full picture, with the receipts.

Signaldefinitive4independent sources

AI coding assistants have a data transmission problem, not necessarily a malicious one, but an invisible one. Most developers using tools like GitHub Copilot, Cursor, Windsurf, Tabnine, or Continue (or terminal agents like Claude Code, Gemini CLI, and Codex CLI) have never watched their own network traffic during a completion request. They've read a privacy page, clicked accept, and moved on. That page is marketing copy with legal hedging. The packets are evidence.

This piece walks through a reproducible methodology for capturing that traffic, documents the transmission patterns that appear across popular tools, stress-tests "local mode" claims, and gives you a practical playbook for controlling what leaves your machine. The goal isn't alarm: it's clarity.


The Test Bench: How to Capture the Traffic#

The methodology matters more than the findings here, because vendor behavior changes with updates and you should be able to reproduce this yourself. The setup is straightforward.

Piece of the benchHow to set it up
Proxy layermitmproxy is the right tool: open source, scriptable, and able to intercept TLS traffic from a local process once you install its CA certificate into your system trust store. Charles Proxy or Proxyman (macOS) do the same job with a GUI. All of them decode HTTPS payloads in full, which is where the interesting data lives
OS-level routingOn macOS, set the system proxy to 127.0.0.1:8080, mitmproxy's default. On Linux, iptables redirect rules or exporting HTTP_PROXY/HTTPS_PROXY before launching your editor both work. Windows sets the system proxy in network settings. One catch: Electron-based editors, VS Code and its forks including Cursor and Windsurf, don't always honour the system proxy, so set it in the editor's own network settings or launch with the environment variables. Terminal agents are usually easiest, since most honour HTTPS_PROXY
Editor isolationRun the IDE in a sandboxed user account or VM with no credentials for anything real, so you don't accidentally exfiltrate actual secrets during the test

Test repository design: Create a synthetic repo that mimics the shape of sensitive code without being actually sensitive. Include:

  • A .env file with fake API keys in recognizable formats (e.g., strings that look like AWS access keys but aren't)
  • A file with a plausible-looking internal function name (calculateRiskScore, applyProprietaryDiscount)
  • A configuration file with internal hostname patterns (internal.corp.example.com)
  • Comments referencing a fake unreleased product name

Open all files in your editor before triggering completions. This maximizes the context window that tools can sample from and gives you a clear test of what gets included in payloads.

Capture triggers: test three distinct events separately, logging the full request URL, headers and body for each.

The eventHow to trigger it
Idle keystrokeType a character and stop
Explicit completion requestTrigger an inline suggestion manually
Chat submitSend a question that references the open file

Limitations to be honest about: You're seeing what leaves the client. You cannot see what the vendor does with that data server-side: whether it's logged, deduplicated, retained, or fed into training pipelines. TLS inspection only gets you to the edge of their infrastructure.

Two client-side caveats also matter. First, WebSocket streams: some tools push completions over WebSockets, and mitmproxy intercepts those natively (each frame shows up in the flow detail, no special flag required). (The --ssl-insecure flag people reach for is unrelated; it tells mitmproxy to skip verifying the upstream server's certificate, which you occasionally need when a backend uses a cert mitmproxy can't validate.) Second, and more serious: certificate pinning. A tool that pins its server certificate rejects mitmproxy's injected CA outright: you'll watch the connection open and immediately fail, and you won't be able to read the payload at all. Some native desktop apps and hardened extensions do this. Getting past it means patching the client or hooking it with something like Frida to strip the pin, which is beyond a quick audit and may run afoul of the tool's terms. If a tool's traffic is pinned, treat the opacity itself as a finding: you're being asked to trust it without any way to verify.


What Fires on Keypress: Mapping the Transmission Triggers#

Across the tools most developers use, a few transmission patterns emerge consistently when you watch the proxy.

What firesWhat it sends
Full-file context on completionMost cloud-based tools don't just send the current line. They send a window: typically the content before and after the cursor, sometimes the entire current file, and in some cases a selection of recently viewed files. The payload is usually JSON with fields like prefix, suffix, filename, language, and increasingly a context array containing snippets from other open files
Idle telemetrySeveral tools make network calls during editor idle time, not just on completion triggers: session identifiers, editor version, workspace hashes, feature-flag checks. The concern is the workspace hash. It doesn't send code, but a hash of your project directory structure fingerprints your codebase and confirms that a specific project exists on your machine
Chat requestsChat submissions almost universally send the full active file plus the conversation history, and some tools append automatically detected "workspace context": a retrieval pass over your project. This is where the broadest sweeps happen. A chat request asking "how does this function work?" may ship considerably more of your codebase than the equivalent inline completion
Destination hostnamesCloud-backed tools route completion traffic to their own inference infrastructure; for GitHub Copilot that's *.githubcopilot.com. Every vendor uses its own domains and they change across versions, so read the hostnames in your own capture rather than trusting a published list. Telemetry often goes to a separate endpoint, sometimes a third-party analytics provider: two hostnames in one completion event means two organizations potentially receiving data

The critical observation: that context array often includes files you haven't explicitly referenced. Tools that index your workspace for retrieval-augmented completion will pull related files into the payload silently. If your .env is open in a background tab and the tool's context-gathering logic scores it as relevant, it may travel in that array.


'Local Mode' Under the Microscope: Do Air-Gap Claims Hold?#

Several tools advertise a "local" or "privacy" mode, and this is where the gap between marketing and packet inspection is most pronounced.

True local inference, a tool like Continue pointed at a locally hosted runtime such as Ollama or LM Studio, running an open-weight coding model (a Qwen or DeepSeek coder, say), produces a verifiably different traffic pattern. Completion requests go to 127.0.0.1 or localhost, not an external hostname. No code leaves the machine. This is reproducible and confirmable in about two minutes with mitmproxy.

But "local mode" in some commercial tools means something narrower. The model inference may be local while licensing verification, telemetry, and crash reporting still hit external servers. When testing, filter your proxy capture for any non-loopback connection during an editing session. A true air-gap should produce zero external connections after initial authentication. Several commercial tools fail this test: they continue to phone home on idle with session pings even when local inference is enabled.

Licensing pings are the most common survivor. Tools that require a valid subscription to unlock local mode must periodically verify that subscription. That verification request typically carries a device identifier and timestamp. It doesn't carry code, but it does tell the vendor that a specific licensed user is actively coding at a given time: a metadata trail.

If air-gap compliance is a hard requirement, a regulated environment or classified contract work, only fully open-source toolchains with self-hosted inference satisfy it without reservation.

Any commercial tool with a cloud-based license server has at minimum a metadata channel you cannot close.


Reading the Fine Print vs. Reading the Packets: Where Terms and Reality Diverge#

Vendor privacy pages typically cover three things: what data is collected, how long it's retained, and whether it's used for model training. The language is almost always ambiguous in the same specific ways.

Where the policy goes vagueThe question it doesn't answer
Training opt-outsMost enterprise tiers offer one, but the default for consumer and free tiers often permits the vendor to use submitted prompts and completions to "improve" their models: human review, automated distillation into fine-tuning datasets, or both. Does the opt-out apply retroactively to data already submitted, or only prospectively? Most policies are silent on this
Retention windowsPolicies commonly say "we retain prompt data for up to X days" without specifying whether the clock starts at submission or at the end of your billing period, or whether derived data (embeddings, feature vectors) falls under the same window. An embedding of your code is not your code, but it encodes structural information about it
Enterprise vs consumerEnterprise tiers typically add no training on customer data (contractually guaranteed, not just policy), data residency options, audit logs and sometimes dedicated inference infrastructure. What they rarely change: the breadth of context sent per request, the telemetry collection pattern, or the crash-reporting pipeline. A stronger legal instrument, not a different transmission profile

The honest framing: an enterprise contract converts a privacy policy (which the vendor can change unilaterally) into a contractual obligation they can be sued for breaching. That's genuinely meaningful. It's not the same as the data not being transmitted.


The High-Value Targets: Code That Carries the Most Exposure#

Not all code is equally sensitive in context. These categories warrant explicit attention:

The categoryWhy it carries the exposure
Secrets in contextAPI keys, database connection strings, JWT signing secrets and OAuth credentials sit in .env files, config initializers and test fixtures that developers leave open while coding nearby. If those files enter the context window, the secrets travel with them. The highest-severity category: a credential in a log or a training dataset is a live vulnerability
Internal API surfaceFunction names, internal SDK method signatures and proprietary protocol structures reveal your architecture to anyone who can read the training data or the logs. Even without business logic, knowing that applyProprietaryPricingEngine() exists and what its parameters look like is competitively sensitive for some organizations
Unreleased feature logicCode for features not yet shipped describes your product roadmap. If it sits in your working tree and your editor indexes the workspace, it can enter completion payloads before the feature ships
PII in test fixturesDevelopers sometimes use real or realistic personal data in unit test fixtures. Names, email addresses and partial account numbers in a test file enter the context window the same way any other file does

The common thread: these categories become risks not because you explicitly shared them, but because your context window is broader than you think and you never checked.


Your Egress Playbook: Practical Controls You Can Apply Now#

These controls are tool-agnostic and additive: stack as many as your threat model requires.

Context hygiene first: Only open files you're actively working on. Close background tabs with config files, .env files, and test fixtures before using AI completion. This is low-tech but directly reduces the surface area of what can enter a context window.

Know your tool's exclusion mechanism: they all differ: There is no universal .aiignore standard yet, and the differences matter.

The toolIts exclusion mechanism
GitHub CopilotContent exclusions, configured in GitHub org or repository settings as glob paths (secrets.json, *.cfg, /scripts/**), not a file in your repo. Business and Enterprise plans only: individual and free Copilot has no exclusion mechanism at all. They have holes too, with no coverage for symlinks, and they don't apply in Copilot's CLI, cloud agent or IDE Agent mode
Cursor.cursorignore blocks the file from the model entirely; .cursorindexingignore keeps it out of the background index but still lets you @-mention it on demand. Cursor also honours your .gitignore
Gemini Code Assist.aiexclude, same syntax as .gitignore
Gemini CLI.geminiignore

Whatever your tool, put .env, *.pem, *secret*, *credential*, and any fixtures with real data on the list: then confirm with a proxy capture that the exclusion is actually honored. "Ignored" is a vendor claim like any other.

The controlWhat it buys you
Egress firewall rulesOn corporate networks, a DNS- or IP-based egress policy that blocks known AI completion endpoints is the most reliable control, enforced regardless of individual developer behaviour. Locally, Little Snitch (macOS) or OpenSnitch (Linux) do the same at the application layer
Secrets scanning pre-commitgit-secrets, TruffleHog and gitleaks run as pre-commit hooks and flag credential patterns before they get committed. They also tell you whether those patterns exist in your working tree at all, which is a useful prompt to close those files before an AI session
Self-hosted or local inference for sensitive workFor the highest-sensitivity code, designate a workflow where AI assistance is either disabled or routed through a self-hosted model. It doesn't have to cover all work: even a convention of "no cloud AI on files in /internal/" reduces exposure meaningfully
Audit your own trafficRun the mitmproxy test described above on your actual working environment. It takes under an hour and gives you ground truth about what your specific tool and configuration transmits. Do it once, then repeat after major tool updates

What We Still Can't See: Honest Gaps#

Proxy inspection gets you client-side truth, when the client lets you have it. It doesn't get you server-side reality. You can confirm that a payload was sent; you cannot confirm what the vendor does with it once it arrives.

Vendors can change their transmission behavior in an update. The tool you tested this month may behave differently next month. Treat your traffic audit as a periodic check, not a one-time certification.

Embeddings and derived representations are invisible to you. If a vendor's system converts your code snippet into a vector embedding for retrieval or fine-tuning, that embedding may persist long after any raw code retention window expires. Current privacy frameworks are still catching up to this distinction.

Finally, enterprise contracts give you legal recourse, not technical certainty. You're trusting a vendor's infrastructure controls and audit commitments. For most organizations that's an acceptable risk posture. For classified or highly regulated environments, it isn't, and the only alternative is eliminating the external channel entirely.


Key takeaways:

The takeawayWhat it means for you
Run mitmproxy during an actual coding sessionDo it before trusting any privacy claim. The setup takes less than an hour
Context windows are broader than most developers assumeClose sensitive files before AI sessions
"Local mode" frequently means local inference, not zero external connectionsVerify it with a proxy
Enterprise tiers provide contractual protectionNot a different data transmission architecture
The highest-risk payloads are credentials, internal API shapes and PII in test fixturesNot business logic
Egress firewall rules and your tool's exclusion list are the most reliable controlsThey don't depend on developer discipline. Verify that the exclusions actually hold

This article is informational and does not constitute legal or compliance advice. Organizations in regulated industries should consult qualified counsel before adopting any data-handling policy.

Sources

  1. GitHub, Responsible use of GitHub Copilot featuresdocs.github.com
  2. GitHub, Copilot documentationdocs.github.com
  3. Cursor, documentation (agent, rules, MCP)cursor.com
  4. Carlini et al., Extracting Training Data from Large Language Models (USENIX Security '21)usenix.org
  5. mitmproxy, the interactive HTTPS proxymitmproxy.org

Ask about this article

Answered only from this piece. The AI never invents.

React
ShareXLinkedInBluesky

More in securityMore in security

Discussion