[BUG] Windows clipboard write exposes content in PowerShell argv (captured by EDR/SIEM ProcessCommandLine telemetry)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
On Windows, Claude Code's clipboard write mechanism passes the copied content as a base64-encoded literal in the command-line arguments of a spawned PowerShell subprocess. This affects BOTH the /copy slash command AND ordinary terminal text selection in the Claude Code TUI — both code paths produce the same leak pattern in ProcessCommandLine. The result is leakage of all copied/selected content into EDR / SIEM telemetry pipelines (Microsoft Defender for Endpoint, CrowdStrike Falcon, SentinelOne, Sysmon EID 1) with default 30-day retention.
The base64 layer is trivially reversed and is itself a known suspicious pattern that EDRs explicitly hunt for — so this both leaks user data AND looks suspicious to security tooling.
Observed pattern in DeviceProcessEvents.ProcessCommandLine:
powershell.exe -NoProfile -Command "Set-Clipboard -Value ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('<BASE64_OF_RESPONSE_CONTENT>')))"
Empirically reproducible against MDE Advanced Hunting telemetry: copied content is fully recoverable from the base64 in ProcessCommandLine. Both code paths produce the leak: confirmed via /copy and via plain terminal text selection (independent triggers, identical telemetry pattern).
What Should Happen?
Clipboard writes should NOT expose the copied user content in process command-line arguments captured by EDR telemetry. The content should be passed via a channel that is not captured in ProcessCommandLine. Three options, in order of preference:
- Pipe via stdin (preferred — what
clipboardy, the standard Node.js clipboard library, already does on Windows):
``powershell``
powershell.exe -NoProfile -Command "[Console]::In | Set-Clipboard"
Then write the content to the spawned process's stdin. Content never appears in argv.
- Use a Node.js native Windows clipboard binding (NAPI module calling
OpenClipboard/SetClipboardDatadirectly). Zero subprocess.
- Use
-EncodedCommandfor a small wrapper script that reads stdin (the script itself ends up in argv, but not the user content).
Same fix logic applies on macOS (pbcopy via stdin, not argv) and Linux (xclip -selection clipboard via stdin) — see Additional Information for the cross-platform concern.
Error Messages/Logs
# Reproduction query (MDE Advanced Hunting):
DeviceProcessEvents
| where Timestamp > ago(1h)
| where InitiatingProcessFileName =~ "claude.exe"
or InitiatingProcessParentFileName =~ "claude.exe"
| where ProcessCommandLine has "Set-Clipboard"
and ProcessCommandLine has "FromBase64String"
| project Timestamp, ProcessCommandLine
# Each row contains the entire selected/copied content, base64-encoded.
# Decoded with [Convert]::FromBase64String($base64) in PowerShell,
# or with base64_decode_tostring() in KQL.
# Observed pattern (sanitized — actual base64 redacted):
powershell.exe -NoProfile -Command "Set-Clipboard -Value ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('<BASE64_OF_RESPONSE_CONTENT>')))"
Steps to Reproduce
- SETUP CAVEAT — Verified ONLY with
CLAUDE_CODE_NO_FLICKER=1env flag enabled (opt-in alt-screen rendering per Claude Code changelog). Default rendering path not verified.
Whether the same leak occurs with the default rendering path (flag absent or unset) has NOT been verified. Maintainers should A/B test both paths to confirm scope.
- On Windows, install Claude Code (any recent version, confirmed on v2.1.119).
- Have an SIEM / EDR running that captures
ProcessCommandLine— MDE Plan 1/Plan 2 surface it in the cloudDeviceProcessEventstable. - Launch Claude Code in any terminal (Windows Terminal, Git Bash, etc.).
- Trigger a clipboard write via EITHER of the two known paths:
- Path A —
/copyslash command: type/copyin the Claude Code TUI. - Path B — terminal text selection: select any text in the Claude Code TUI with the mouse — selection alone triggers the same code path (no Ctrl+C needed when
copy on select = true, which is the Claude Code default).
Both paths produce the same Set-Clipboard PowerShell subprocess pattern in EDR telemetry.
- Wait a few seconds for telemetry ingestion, then query the EDR. With MDE Advanced Hunting:
``kql``
DeviceProcessEvents
| where Timestamp > ago(1h)
| where InitiatingProcessFileName =~ "claude.exe"
or InitiatingProcessParentFileName =~ "claude.exe"
| where ProcessCommandLine has "Set-Clipboard"
and ProcessCommandLine has "FromBase64String"
| project Timestamp, ProcessCommandLine
- Each row contains the entire selected/copied content, base64-encoded inside a
Set-Clipboard -Value ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('...')))literal. - Decode any row's base64 with
[Convert]::FromBase64String($base64)in PowerShell orbase64_decode_tostring()in KQL — the original copied text is recovered verbatim.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.119
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
Impact
- On configurations where the host EDR or SIEM captures
ProcessCommandLine(e.g., Microsoft Defender for Endpoint Plan 1/2 by default, CrowdStrike Falcon, SentinelOne, or Sysmon EID 1 forwarded to a SIEM such as Splunk / Microsoft Sentinel), every clipboard write in the Claude Code TUI on Windows — whether via/copyor via plain mouse text selection — exposes the copied content in the captured telemetry. On MDE specifically, default Advanced Hunting retention is 30 days; the base64-encoded literal is trivially decodable. - Cloud-hosted EDR telemetry has historical compromise precedents (e.g., Storm-0558, 2023). Any future compromise of the EDR backend would expose every Claude Code interaction copied via this mechanism.
- The base64 layer provides zero privacy benefit. It only adds suspicious-looking telemetry: EDRs specifically watch for
FromBase64Stringin PowerShell command lines as an obfuscation indicator (well-known threat hunting pattern in Splunk / Sentinel / MDE built-in detections). So this both leaks user data AND triggers heuristic alerts on legitimate Claude Code usage.
Cross-platform concern
Based on near-miss issue #41954, a similar pattern exists on macOS (pbcopy) and Linux (xclip). If those tools receive the content via argv (rather than stdin), they leak the same way to macOS EDR (CrowdStrike, Jamf telemetry) and Linux auditd / EDR (Wazuh, Falco, etc.). Recommend auditing all three platforms — the clipboardy reference implementation already handles this correctly cross-platform via stdin streams, so it can serve as a template for the fix.
Related (verified not duplicates)
- #41954 — TUI selection spams clipboard on every render (macOS/Linux pbcopy/xclip). Behavioral overlap, but does not mention Windows / EDR / argv-vs-stdin / privacy implications. Could be merged or cross-linked.
- #42417 — OSC 52 mojibake (Windows encoding bug, unrelated to this).
- #18653 — Tool result content sanitization hook (different scope).
- #44868, #44909 — Read/grep secret leaks into model context (different vector — input to model, not output to host clipboard).
---
Issue investigated and drafted with Opus 4.7 (Anthropic).
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗