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
The Real Privacy Audit: What Data Your AI Coding Assistant Sends Home

ArticlesecurityDeep read

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

BitByteCore Security DeskAug 5, 202611 min

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.

Signaldefinitive3independent 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.

Proxy layer: mitmproxy is the right tool. It's open source, scriptable, and can intercept TLS traffic from a local process once you install its CA certificate into your system trust store. If you prefer a GUI, Charles Proxy or Proxyman (macOS) do the same job with visual inspection. All of them decode HTTPS payloads in full, which is where the interesting data lives.

OS-level routing: On macOS, set your system proxy to route traffic through 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 users set the system proxy in network settings. One catch: Electron-based editors — VS Code and its forks, which includes Cursor and Windsurf — don't always honor the system proxy. If your capture comes up empty, set the proxy in the editor's own network settings or launch it with the proxy environment variables. Terminal agents are usually the easiest to capture, since most honor HTTPS_PROXY.

Editor isolation: Run your IDE in a sandboxed user account or VM that has no credentials for anything real. This is important — you don't want to 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 and log them: (1) idle keystroke — type a character and stop, (2) explicit completion request — trigger inline suggestion manually, (3) chat submit — send a question that references the open file. Log the full request URL, headers, and body for each.

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.

Full-file context on completion: Most cloud-based tools don't just send the current line. They send a window of context — 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.

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.

Idle telemetry: Several tools make network calls during editor idle time — not just on completion triggers. These are typically smaller pings: session identifiers, editor version, workspace hashes, or feature-flag checks. On their own, these seem benign. The concern is the workspace hash: if a tool is computing a hash of your project directory structure and reporting it, that hash is fingerprinting your codebase. It doesn't send code, but it does confirm that a specific project exists on your machine.

Chat requests: Chat submissions almost universally send the full active file as context plus the conversation history. Some tools also 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 hostnames: Cloud-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 any published list. Telemetry often goes to a separate endpoint — sometimes a third-party analytics provider. Two different hostnames in a single completion event means two organizations potentially receiving data.


'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.

The practical takeaway: if air-gap compliance is a hard requirement (regulated environment, 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.

Training opt-outs: Most enterprise tiers offer a training opt-out, but the default for consumer or free tiers often permits the vendor to use submitted prompts and completions to improve their models. "Improve" is doing significant work in those sentences. It can mean human review, automated distillation into fine-tuning datasets, or both. The key question to ask of any policy: does the opt-out apply retroactively to data already submitted, or only prospectively? Most policies are silent on this.

Retention windows: Policies commonly state something like "we retain prompt data for up to X days." What they rarely specify is whether that retention clock starts at submission or at the end of your billing period, and whether aggregated or derived data (embeddings, feature vectors) is subject to the same window. An embedding of your code is not your code, but it encodes structural information about it.

Enterprise vs. consumer delta: The difference is real but often overstated. Enterprise 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. You're getting a stronger legal instrument and sometimes better data isolation, not a fundamentally different data 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:

Secrets in context: API keys, database connection strings, JWT signing secrets, and OAuth credentials often appear in .env files, config initializers, or test fixtures that developers leave open while coding nearby. If those files enter the context window, the secrets travel with them. This is the highest-severity category — a credential in a log or a training dataset is a live vulnerability.

Internal API surface: Function 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 logic: Code for features not yet shipped describes your product roadmap. If that code is in your working tree and your editor indexes the workspace, it can enter completion payloads before the feature ships.

PII in test fixtures: Developers sometimes use real or realistic personal data in unit test fixtures. Names, email addresses, and partial account numbers in a test file can 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.

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

Egress firewall rules: On corporate networks, a DNS- or IP-based egress policy that blocks known AI completion endpoints is the most reliable control — it's enforced regardless of individual developer behavior. Locally, Little Snitch (macOS) or OpenSnitch (Linux) let individual developers do the same at the application layer.

Secrets scanning pre-commit: Tools like git-secrets, TruffleHog, or gitleaks run as pre-commit hooks and flag credential patterns before they get committed — but 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 work: For the highest-sensitivity code, designate a workflow where AI assistance is either disabled or routed through a self-hosted model. This doesn't have to be all work — even a convention of "no cloud AI on files in /internal/" reduces exposure meaningfully.

Audit your own traffic: Run 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 is transmitting. 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:

  • Run mitmproxy during an actual coding session before trusting any privacy claim — the setup takes less than an hour.
  • Context windows are broader than most developers assume; close sensitive files before AI sessions.
  • "Local mode" frequently means local inference, not zero external connections — verify with a proxy.
  • Enterprise tiers provide contractual protection, not a different data transmission architecture.
  • The highest-risk payloads are credentials, internal API shapes, and PII in test fixtures — not business logic.
  • Egress firewall rules and your tool's exclusion list are the most reliable controls because they don't depend on developer discipline — but verify 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

Ask about this article

Answered only from this piece — the AI never invents.

React
ShareXLinkedInBluesky

More in securityMore in security

Discussion