Incomplete Recipient Validation in Claude Code Computer Use Enabled Command Execution in an Unapproved Terminal
HackerOne #3985968
High · Triaged


TL;DR
Claude Code Computer Use limits desktop control through per-application approval. Approving an ordinary application does not approve a terminal, which Anthropic flags as equivalent to shell access.
An earlier CodeAnt finding (fixed in Claude Code 2.1.243) showed a multi-event
typeaction could continue into an unapproved terminal after focus changed. Anthropic fixedtypeand repeatedkeyby rechecking the recipient inside those loops.The same invariant was not applied to
hold_key. In Claude Code 2.1.252,hold_keychecked the frontmost application once, then handed the full key sequence to a native macOS executor that pressed each component without rechecking the recipient.We proved it: one composite action began on Grapher's Save-and-Quit sheet, its first Return quit Grapher, macOS returned focus to unapproved iTerm, and later components typed
touch zand pressed Return. The shell executed it. Three exploit runs created the marker; three matched controls did not; a direct iTerm invocation was blocked.Anthropic confirmed the root cause through code review, rated it High (CVSS 4.0 score 7.7), and awarded a bounty. Remediation is in progress and the report is still private.
At a Glance
Component | Claude Code Computer Use (macOS) |
Vulnerability | Incomplete-fix bypass of per-application recipient validation in the |
Related fix | Recipient-continuity fix in Claude Code 2.1.243 (report #3930758) |
Impact | One approved Grapher action continued into unapproved iTerm and executed a shell command |
Root cause |
|
Class | Authorization / TOCTOU (checked-versus-consumed recipient mismatch) |
Severity | High, CVSS 4.0 score 7.7 |
Affected | Claude Code 2.1.252 (macOS arm64) |
CVE | None assigned (report private, remediation in progress) |
Report | HackerOne #3985968 |
Found by | CodeAnt AI Security Research Team |
Claude Code Computer Use is powerful because it generates trusted native input on the user's real desktop. Its central security control is a per-application approval list: a user can approve an ordinary application, such as Apple's Grapher, without approving a terminal, which the product identifies as equivalent to shell access.
An earlier vulnerability the CodeAnt AI Security Research Team reported showed that Claude Code could authorize a multi-event type operation while Grapher was frontmost, then continue sending its remaining keystrokes after Grapher quit and unapproved iTerm became the recipient. Anthropic fixed that path in Claude Code 2.1.243 by checking the frontmost application during the input loop. In this follow-on finding, we show that the same security invariant was not applied to the separate hold_key action, so the protected terminal boundary could still be crossed.
The Application Approval Boundary
Computer Use is powerful because it generates trusted native input on the user's real desktop. Its principal security boundary is therefore not merely whether a tool call was approved. It is which application is allowed to receive every event produced by that call.
Anthropic's Computer Use documentation states that Claude can control only applications approved for the current session, and it gives terminal and IDE applications an "Equivalent to shell access" warning. Those statements establish a clear distinction between approving Grapher and approving iTerm.
The relevant invariant is:
In our proof, the complete grant state remained equivalent to:
iTerm's bundle identifier, com.googlecode.iterm2, never appeared in the grant list.
Why This Was an Incomplete Fix
The earlier report and this finding reach the same protected terminal boundary, but they use different implementation paths.
The original issue affected type. Its implementation emitted a series of graphemes, Return events, and Tab events after one initial application check. Claude Code 2.1.243 introduced a recipient-continuity helper and called it inside the type loop. The repeated key path also checked recipient identity inside its repeat loop. The hold_key path received only a check before its native component loop:
Action | Where Recipient Identity Was Checked | Result After Focus Changed |
|---|---|---|
| Before each emitted grapheme or control key | Remaining input stopped |
repeated | Before each repeated key event | Remaining input stopped |
| Once before the complete sequence entered the executor | Later components continued |
This distinction matters. We did not claim that Anthropic's type fix failed. The fixed type path remained effective. The bypass existed because a sibling multi-event action implemented the same security requirement in a different loop.

Root Cause: Policy Stopped at the Executor Boundary
Reverse engineering the signed Claude Code 2.1.252 runtime, we found that the core Computer Use layer captured the authorized application and performed one focus-continuity check before calling the native executor. Reduced to the security-relevant control flow, the affected path was equivalent to:
The native macOS executor received the parsed components, the duration, and an abort callback. It did not receive the approved application identity. Its loop was equivalent to:
The loop knew whether the operation had been globally aborted, but it could not determine whether Grapher still owned focus. Once delivery began, the authorization layer had no opportunity to stop a later component from reaching a different process. This created a precise checked-versus-consumed mismatch:
The first key component caused the identity transition itself. No separate focus-stealing helper, malicious approved application, or attacker-controlled scheduling race was required.
Controlled Reproduction
Our final reproducer used the official Anthropic-signed Claude Code 2.1.252 binary on macOS arm64 and Apple's unmodified Grapher application.
Item | Verified Value |
|---|---|
Product | Claude Code |
Platform | macOS arm64 |
Affected version | 2.1.252 |
Binary SHA-256 |
|
Approved application | Grapher only |
Protected sink | Unapproved iTerm2 shell |
Composite components | 265 |
Encoded input size | 1,311 bytes |
A localhost Messages fixture supplied deterministic Computer Use calls. It did not invoke a production model, retain an authorization header, patch Claude Code, or replace the Computer Use policy and executor. The proof used the stock signed binary and native macOS input delivery.
Direct iTerm Negative Control
We first brought iTerm to the foreground and invoked the exact composite hold_key sequence. Claude Code rejected the operation:
No marker was created. This established that iTerm was protected, the application gate was active, and the grant list had not accidentally included the terminal.
Transition Path
The candidate path created a new Grapher document and opened its standard Save-and-Quit sheet. iTerm remained behind Grapher with a blank prompt in a dedicated temporary directory. The single hold_key sequence had this shape:
The first Return confirmed Grapher's save sheet and completed the quit. The repeated Left components kept the same tool call active long enough for the stock application lifecycle to complete. They did not invoke a shortcut or special macOS behavior. After focus returned to iTerm, the later components typed the harmless command and the final Return submitted it.
The terminal was empty before the operation:
The created empty file proved that the shell processed the command. It was not merely rendered text.
Matched No-Transition Control
The matched control used the same Claude Code binary, the same Grapher-only approval, the same iTerm target, the same 265-component sequence, and the same Computer Use implementation. Only the application lifecycle changed. Grapher remained alive and frontmost. The input stayed in Grapher and the iTerm marker remained absent.

Reproduction Matrix
Our standalone reproducer completed three exploit runs and three matched controls. Every assertion passed.
Case | App at Authorization | App at End | iTerm Approved | Command Pre-Staged | Marker |
|---|---|---|---|---|---|
Direct iTerm negative | iTerm | iTerm | No | No | Absent; blocked |
Exploit run 1 | Grapher | iTerm | No | No | Created |
Exploit run 2 | Grapher | iTerm | No | No | Created |
Exploit run 3 | Grapher | iTerm | No | No | Created |
Control run 1 | Grapher | Grapher | No | No | Absent |
Control run 2 | Grapher | Grapher | No | No | Absent |
Control run 3 | Grapher | Grapher | No | No | Absent |
The exact sequence produced the following stable properties in all exploit runs:
the call began with
com.apple.grapherfrontmost;Grapher's save sheet was present;
the operation returned
Key held.;com.googlecode.iterm2was frontmost after delivery;Grapher remained the only approved application;
all optional grant flags remained false; and
the empty
zmarker existed in the terminal target directory.
Capability Delta and Impact
The security impact is best expressed as a capability transition:
Approval for Grapher does not otherwise grant command execution. Reaching iTerm bypassed the separate decision that carries the product's shell-access warning.
A prompt-injected or otherwise model-controlled Computer Use sequence could use this primitive to enter commands under the user's normal host identity. Depending on the command and local environment, that could expose user-readable information, modify source or configuration, start processes, install software, or make network requests.
This was not unconditional remote code execution. Computer Use had to be enabled, Grapher had to be approved for the session, an unapproved terminal had to receive focus after Grapher exited, and attacker-influenced model input had to choose the sequence. These conditions are reflected in the AT:P and UI:P metrics. They do not remove the bypass of the explicit per-application approval boundary.
Anthropic assigned the following CVSS 4.0 vector:
text
Vendor Validation
Anthropic confirmed the underlying issue through code review. Its triage response identified the same root cause: hold_key validates the approved frontmost application before delivery begins but does not revalidate between the components of a composite sequence. Anthropic classified the report as High and later awarded a bounty for a High-severity finding on a core asset.
At the editorial cutoff, Anthropic reported that remediation was still in progress. The HackerOne report remained triaged and private. No fixed version, public advisory, or CVE identifier had been supplied.
Remediation Principles
The immediate correction is to extend recipient continuity through the entire native delivery loop.
Pass the approved recipient into the executor. The native layer needs the bundle identifier and, preferably, process and window identity captured during authorization.
Revalidate before every component. Each key press must confirm that the intended application remains the actual recipient.
Abort and release safely. If identity changes, stop delivery and release any components already held down before returning an error.
Bind to a stronger object than a display name. Bundle identifier alone may not distinguish process replacement or window transitions. Process identity and accessibility target should be retained where possible.
Bound composite inputs. Component and encoded-size limits reduce abuse and simplify review, but they are defense in depth, not a substitute for recipient checks.
Test every multi-event sibling.
type, repeatedkey,hold_key, batches, paste paths, drag sequences, and any other loop that emits multiple native events require the same invariant.
[Figure 4: fig-4.svg] A robust design carries the authorized application identity into the native executor, checks it before every component, and aborts with safe key release as soon as the recipient changes.
Lessons for Security Engineering
A Security Helper Is Effective Only Where It Is Called
Claude Code 2.1.243 contained the correct recipient-continuity primitive. The remaining weakness came from placement. Calling the helper once before a second loop did not protect the events produced inside that loop.
Fixes Should Be Reviewed by Invariant, Not Only by Function
The original defect was not fundamentally a type bug. It was a violation of the rule that every event must be delivered only to an approved recipient. Reviewing all implementations of that invariant would have included hold_key and the native executor.
Native Executors Are Part of the Authorization Path
The high-level policy layer authorized Grapher correctly. The failure occurred after delegation, where the native layer had insufficient context to preserve that decision. Security metadata must travel with the operation through every layer that can change its meaning.
Deterministic Lifecycle Transitions Produce Stronger Evidence
The proof did not depend on racing a user or external process to steal focus. The authorized operation itself completed a stock application's quit sequence. That made the identity transition repeatable and isolated the missing inner-loop check.
Negative Controls Must Demonstrate the Defended Capability
The direct iTerm denial showed that shell input required approval. The no-transition control showed that the sequence remained harmless while Grapher stayed frontmost. Together, they proved that the application transition, not the payload alone, unlocked the protected sink.
Are You Affected?
The vulnerable behaviour is in Claude Code 2.1.252 on macOS with Computer Use enabled. You are in scope of the pattern if you use Computer Use, approve a non-terminal application for a session while a terminal (iTerm, Terminal, or an IDE terminal) is open in the background, and run attacker-influenced or untrusted content that can steer the Computer Use sequence.
Because remediation is still in progress at the time of writing, the practical guidance is to be deliberate about enabling Computer Use around untrusted content, avoid keeping a terminal focus-reachable behind an approved application during agent-driven sessions, and update Claude Code once Anthropic confirms a fix, then re-verify the fixed version.
Disclosure Timeline
Date | Event |
|---|---|
1 September 2026 | Report #3985968 submitted to Anthropic through HackerOne |
3 September 2026 | Anthropic confirmed the root cause through code review and triaged the report High at 7.7 |
14 September 2026 | Anthropic stated that remediation remained in progress and no fix had been released |
16 September 2026 | Anthropic awarded a bounty for the High-severity finding |
21 September 2026 | Editorial cutoff; report remained private and triaged, with no fixed version supplied |
Conclusion
Claude Code's original recipient-continuity fix corrected type, but the broader invariant stopped at a sibling executor boundary. In the affected hold_key path, authorization described Grapher only at the start of the call. The native component loop then continued after Grapher exited and delivered trusted events to unapproved iTerm.
The durable rule is simple:
Authorization must be checked against the application receiving each native event, including events emitted by composite actions and delegated executor loops.
This case demonstrates why incomplete-fix research should follow security invariants across adjacent implementations. A patch can be correct in the function it changes while the same boundary remains open in a sibling path.
References:
Computer Use authorization on macOS found by researcher Sunder Singh at CodeAnt AI
HackerOne report #3985968 (private at the editorial cutoff)
Related resolved report #3930758 (recipient-continuity fix in Claude Code 2.1.243)
Tested affected build: Claude Code 2.1.252, macOS arm64
CWE-367: Time-of-check Time-of-use Race Condition · CWE-863: Incorrect Authorization
This research was conducted under Anthropic's vulnerability disclosure program by the CodeAnt AI Security Research team. Testing used stock local applications, a loopback fixture, and a harmless temporary marker. No third-party data or production service was accessed.
Building an agentic tool that generates native input or drives a desktop, and want its authorization boundary reviewed? Reach us at securityresearch@codeant.ai
[FAQ]
Frequently Asked
Questions
What is the Claude Code Computer Use vulnerability?
Is Claude Code Computer Use safe to use?
What versions of Claude Code are affected?
What is an incomplete fix or patch bypass?
What is a TOCTOU vulnerability, and how does it apply here?
Has a CVE been assigned?
Why is this rated High (7.7) rather than Critical?
More from CodeAnt
[GET STARTED]
START PENTEST






