Stale Application Authorization in Claude Code Computer Use Enabled Cross-Application Keystroke Delivery on macOS
CVSS 4.0

TL;DR
Claude Code Computer Use gates desktop control by per-application approval. A terminal such as iTerm carries a shell-access warning and must be approved separately from an ordinary app.
In Claude Code 2.1.226, a
typeoperation checked the frontmost approved application once, before it started, then emitted every grapheme, Return, and Tab without rechecking the recipient.Researchers at CodeAnt AI used one
typecall that began on Grapher's Save-and-Quit sheet: the first Return saved and quit Grapher, macOS restored focus to an unapproved iTerm window, and the remaining keystrokes and final Return executed a harmless shell command. Only Grapher was ever approved.No focus-stealing race and no malicious application were required. A stock application's normal quit lifecycle caused the transition. This is a stale-authorization (checked-versus-consumed, TOCTOU) bug.
Anthropic rated it High (CVSS 4.0 score 7.7), fixed it in 2.1.243 so input now stops when the approved application loses focus, and resolved the report after a three-run retest.
At a Glance
Component | Claude Code Computer Use (macOS) |
Vulnerability | Stale application authorization in the |
Class | Authorization boundary bypass, checked-versus-consumed (TOCTOU) recipient mismatch |
Chain | One approved Grapher |
Root cause |
|
Affected | Claude Code 2.1.226 (macOS arm64) |
Fixed in | Claude Code 2.1.243 (verified by retest) |
Severity | High, CVSS 4.0 score 7.7 |
CVE | None assigned (report private at editorial cutoff) |
Report | HackerOne #3930758 |
Status | Validated, fixed, and resolved after retest; private at editorial cutoff |
Found by | CodeAnt AI Security Research Team |
Claude Code Computer Use is powerful because it produces trusted native input on the user's real macOS desktop. Its central control is per-application approval: the user approves specific applications for the session, and terminals receive a particularly strong warning because controlling one is equivalent to shell access.
Researchers at CodeAnt AI found that in Claude Code 2.1.226, that approval had a lifetime longer than the approved application itself. A single type operation checked the recipient once, at the start, and then kept delivering keystrokes after focus moved to an application the user never approved. Here is the whole finding.
The Security Boundary
Computer Use approval is not a grant to control the desktop as a whole. It is a grant to control specific applications for the current session. Anthropic's Computer Use documentation distinguishes applications by risk and describes terminal or IDE approval as equivalent to shell access.
That design implies an event-recipient invariant:
The relevant authorization object is not only the tool call. It is the application, process, window, and accessibility target that receives each event produced by that call.
In the controlled session, the entire grant state was equivalent to:
iTerm's bundle identifier, com.googlecode.iterm2, was absent before and after the operation.
Why Grapher Produced a Deterministic Transition
Early experiments with ordinary focus changes were unsuitable because they depended on scheduling and could be dismissed as unreliable desktop behavior. The final proof instead used a stock application lifecycle that the input operation itself completed.
The sequence was:
Open a fresh document in Apple's Grapher.
Select Grapher > Quit so the standard Save-and-Quit sheet appears.
Keep a dedicated iTerm window behind Grapher.
Start one Computer Use
typecall while Grapher and its save sheet are frontmost.Use the first Return in that call to confirm the save and complete Grapher's quit.
Observe macOS transfer focus to the existing iTerm window.
Observe the same
typecall continue emitting its remaining characters.
The call did not pause for a second Claude Code authorization decision when the recipient changed. It retained the decision made for Grapher and delivered the rest of the input to iTerm.
The proof used a long, controlled payload and a harmless marker command. The marker established that the final Return was not merely displayed in a terminal: the shell actually processed the command.
Root Cause: One Check Before a Multi-Event Loop
Reverse engineering the signed 2.1.226 runtime, we isolated two functions in the extracted JavaScript. The minified names are included to make the analysis reproducible, but the excerpts below are reduced to the security-relevant control flow.
The Application Check
The function identified as fet obtained the frontmost application and looked up its bundle identifier in the session grant list. If the application was not approved, it returned app_not_granted:
That check worked correctly when iTerm was already frontmost.
The Input Loop
The function identified as _Ly called the application check once and then entered a loop over the complete text:
No check inside the loop verified that Grapher remained frontmost. Return could close a sheet, close a window, quit an application, or submit an action that moved focus elsewhere, yet every later event inherited the original authorization.

The mismatch can be stated precisely:
The approval was valid at the time of the check. It became invalid when the event recipient changed, but the operation had no mechanism to notice.
Controlled Reproduction
Our final reproducer used the official Anthropic-signed Claude Code binary and Apple's unmodified Grapher application.
Item | Verified value |
|---|---|
Product | Claude Code |
Platform | macOS arm64 |
Affected version | 2.1.226 |
Affected binary SHA-256 |
|
Extracted JavaScript SHA-256 |
|
Approved application | Grapher only |
Unapproved sink | iTerm2 |
A localhost Messages API fixture supplied deterministic Computer Use actions. It did not call a real model, retain an authorization header, patch Claude Code, or contact a production service. The proof created only a temporary local marker and cleaned up its dedicated Grapher and iTerm state.
Direct iTerm Negative Control
With iTerm frontmost, we requested the same Computer Use input directly. Claude Code rejected it because iTerm was not in the approved application list. No marker was created. This control established three important facts: the per-application gate was active; iTerm had not been accidentally approved; and the payload did not execute without the lifecycle transition.
Grapher Transition Candidate
The candidate began with Grapher's Save-and-Quit sheet frontmost. The one type call then crossed this sequence:
All three clean runs produced the CUCANARY marker. The grant list still contained only Grapher after execution.
No-Transition Control
The matched control used the same payload, the same Grapher grant, and the same native save sheet, but it did not take the quit path. Grapher remained frontmost, the input stayed inside Grapher, and the iTerm marker remained absent. This control isolated the security-relevant variable: whether the approved recipient changed during the call.

Case | App at Authorization | App After First Return | Result |
|---|---|---|---|
Direct iTerm control | iTerm, unapproved | iTerm | Blocked with |
Grapher transition, run 1 | Grapher, approved | iTerm, unapproved | Marker created |
Grapher transition, run 2 | Grapher, approved | iTerm, unapproved | Marker created |
Grapher transition, run 3 | Grapher, approved | iTerm, unapproved | Marker created |
No-transition control | Grapher, approved | Grapher, approved | Input stays in Grapher; no marker |
Capability Delta and Impact
The capability delta was not simply that focus changed. It was that a payload denied at the terminal boundary became executable after starting in a lower-risk approved application:
A model-controlled or prompt-injected Computer Use sequence could therefore convert approval for an ordinary application into terminal authority that the user had deliberately not granted. Once input reaches a live shell, it can act with the user's normal host privileges, including reading user-accessible data, changing code or configuration, starting processes, and making network requests.
The issue was not unconditional remote code execution. Computer Use had to be enabled, the user had to approve Grapher for the session, an iTerm window had to be available to receive focus, and attacker-influenced model input had to steer the sequence. These requirements explain the AT:P and UI:P metrics in Anthropic's assessment. They do not remove the bypass of the explicit terminal approval boundary.
Anthropic assigned this CVSS 4.0 vector:
Fix and Independent Retest
Anthropic released a fix in Claude Code 2.1.243. The retest used the stock signed macOS arm64 binary with SHA-256:
The original reproducer was retained. Only the expected affected version and result changed. Grapher remained the sole approved application, direct iTerm input remained denied, and the same Save-and-Quit lifecycle still transferred focus to iTerm.
In three clean retest runs, Claude Code detected the recipient change and stopped the type operation after 66 of 765, 65 of 765, and 66 of 765 graphemes. The remaining command text was not delivered, the final Return did not reach iTerm, and the marker was absent in every run.
The matched no-transition control kept Grapher frontmost. All 765 graphemes completed normally and no iTerm marker appeared. This confirmed that the fix did not simply disable type; it terminated the operation specifically when the approved recipient ceased to be frontmost.

Are You Affected?
The vulnerable behavior is in Claude Code 2.1.226 on macOS with Computer Use enabled, and it was fixed in 2.1.243. If you use Computer Use, confirm you are on 2.1.243 or later, where a type operation stops as soon as the approved application loses focus. Check your version with claude --version; standard auto-update should already have carried the fix. Until you have confirmed the fixed version, be deliberate about running Computer Use where an approved application's normal quit or close can hand focus to an unapproved terminal or IDE.
Remediation Principles
The immediate fix is to stop emitting input once the authorized application is no longer the recipient. A robust design should enforce several related properties.
Revalidate every emitted event. Check the recipient before each grapheme, Return, Tab, click, or repeated key event.
Bind more than the display name. Track the bundle identifier, process identity, window, and relevant accessibility target so a replacement or lifecycle transition cannot inherit approval.
Abort on recipient change. Do not continue after a focus transition and do not silently move the remaining input to another application.
Treat multi-event calls as sequences of security decisions. A single tool invocation is not a single recipient when it can emit hundreds of native events.
Test lifecycle-changing input. Regression coverage should include save sheets, quit dialogs, window closure, application launch, modal dismissal, registered file handlers, and other actions that can change the frontmost principal.
Apply the invariant to composite actions. Batch input, held keys, repeated keys, paste operations, drag sequences, and keyboard shortcuts require the same recipient continuity.
Lessons for Agentic Desktop Security
This vulnerability illustrates a common authorization error in systems that translate one high-level AI action into many native operations.
Approval Must Follow the Consumed Object
The user approved Grapher, not a sequence of bytes independent of its destination. Once iTerm became the recipient, the original decision no longer described the action being performed.
Tool-Call Boundaries Are Not Always Security Boundaries
One type call appeared atomic at the protocol layer but was implemented as hundreds of separately delivered events. Security checks placed only at the protocol boundary could not account for state changes inside the loop.
Deterministic Lifecycle Transitions Make Stronger Evidence
A stock Save-and-Quit sequence removed the ambiguity of a timing race. The authorized operation itself caused the transition, which made the checked-versus-consumed mismatch directly reproducible.
Negative Controls Must Prove the New Capability
The direct iTerm denial showed that shell input was protected. The no-transition control showed that the payload did not reach iTerm while Grapher stayed alive. Together, they established that stale authorization, rather than test setup, granted the new capability.
Disclosure Timeline
Date | Event |
|---|---|
11 August 2026 | Report #3930758 submitted to Anthropic through HackerOne |
12 August 2026 | Anthropic reproduced the code-level issue and triaged it High at 7.7 |
25 August 2026 | Anthropic released the fix in Claude Code 2.1.243 and requested a retest |
25 August 2026 | Three affected-path retests failed safely and the matched control remained functional |
26 August 2026 | Anthropic approved the retest, awarded the bounty, and resolved the report |
At the editorial cutoff, the report had not been publicly disclosed and no CVE identifier or public advisory was available.
Conclusion
Claude Code correctly rejected direct input to unapproved iTerm, but the affected type implementation did not preserve that decision when focus changed inside the operation. By checking once and consuming many times, it allowed approval for Grapher to survive beyond Grapher's lifetime and reach a shell-capable application.
The durable security rule is concise:
Every native input event must be authorized against the application that will receive that event, not the application that happened to be frontmost when a longer operation began.
Anthropic's 2.1.243 fix restored that invariant in the tested path by stopping the remaining keystrokes as soon as Grapher ceased to be frontmost.
References:
HackerOne report #3930758 (private at the editorial cutoff)
Tested affected build: Claude Code 2.1.226, macOS arm64
Tested fixed build: Claude Code 2.1.243, macOS arm64
CWE-367: Time-of-check Time-of-use Race Condition · CWE-863: Incorrect Authorization
This research is part of an ongoing effort by CodeAnt AI Security Research to audit the trust boundaries in agentic development tools. It was conducted under Anthropic's vulnerability disclosure program; the proof of concept used stock local applications, a loopback fixture, and a harmless temporary marker, and no third-party data or production service was accessed.
Building an agentic tool that drives a desktop or an IDE and want its authorization boundary reviewed? Reach us at securityresearch@codeant.ai
[FAQ]
Frequently Asked
Questions
Is Claude Code Computer Use safe to use?
What was the Claude Code focus-transition (type) vulnerability?
Which Claude Code versions are affected, and is there a CVE?
What is a stale-authorization or checked-versus-consumed (TOCTOU) bug?
How did Anthropic fix it?
How can developers prevent this class of bug in agentic desktop tools?
Can a prompt injection trigger this Claude Code Computer Use bug?
More from CodeAnt
[GET STARTED]
START PENTEST






