hook: ui-input-guard blocks synthetic input at the user's live session - #291
Conversation
|
This pull request is part of a Mergify stack:
|
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c477b065-d373-4be7-ba2a-80bb72cda3e8) |
bad10af to
2d22904
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3d29e9ae-85c3-40c3-858e-40c0c5c015df) |
Revision history
|
2d22904 to
445e5b0
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a5a21c1a-58bc-4cb1-87c9-70a747c55385) |
AppleScript System Events keystrokes and clicks, cliclick, xdotool, screencapture video, and ffmpeg screen capture act on the session the user is sitting in. They are blocked unless a hands-off window marker is open and fresh, the screen is unlocked, and the user has been idle a moment. A command that runs a local script is scanned through that script, with shell variables in the path resolved first, and files are streamed rather than skipped for being large: an unchecked file is not a clean file. Past the scan ceiling the command is refused with the reason. Ships with its own installer wiring, since the repo's install test requires every hook entrypoint to be wired in the commit that adds it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KU2pPKob4MJ1NqjsfTNyYJ Change-Id: I670196cdbe46ac0dad0cd9c097033d312f1cffb6
445e5b0 to
3eea768
Compare
817ee2a to
2d1bff8
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c041be79-a8ab-4f3e-a4ae-1c572be8cabb) |
314f044
into
stack/EdbertChan/reflect/ui-input-guard-hook-freshness-20260908/hook-freshness-warns-checkout-behind-hooks-stale--e2558c7a
Summary
Synthetic input acts on the session the user is sitting in. Typed into the wrong window it sends real messages and trips real shortcuts; a screen recording captures whatever they have open.
In one session an agent drove the user's Slack with AppleScript keystrokes while they were working in another app. Later keystrokes went into the macOS lock screen, and a stray message plus an accidental pin landed in their workspace. Across the transcript corpus, 3 sessions issued 17 such commands, 13 of them in that one.
This blocks those commands unless the user has granted a hands-off window, the screen is unlocked, and they have been idle a moment.
Backtested over every Bash command in the local transcript corpus: 41,152 commands, 22 flagged (0.053%) across 3 sessions. Every remaining hit was audited by hand and is a real input-driving or screen-capture call. Five false positives the backtest exposed are now fixtures: a
git grepwhose pattern lists the mechanisms, awhichprobe, a commit message naming them, and code holding them as literals in a heredoc or behindpython3 -c.The same backtest exposed two silent skips that reported unchecked commands as clean: a wrapper script reached through a shell variable was never resolved, and a script over 64 KB was skipped rather than read. Paths are now resolved, files are streamed in chunks, and a file past an 8 MB ceiling or unreadable is refused with its path and reason instead of assumed safe.
Review Claim
A Bash command that synthesizes input or records the screen is blocked unless a fresh hands-off marker exists, the screen is unlocked, and the user is idle.
Review Lane
behavior
Review Unit
tooling-policy
Safety Invariant
Only Bash commands carrying a named mechanism are considered: AppleScript
System Eventswithkeystroke,key code, orclick at;cliclick;xdotool;screencapture -V;ffmpegon anavfoundationscreen device. The lock and idle probes fail open, so a probe error cannot block a clean command; a missing marker still blocks. Authoring a driver script through a write heredoc, and read-only search pipelines whose pattern merely contains the words, stay silent.Slice Rationale
One mechanism, one commit, wiring included. The repo's install test requires every hook entrypoint to be wired in the commit that adds it, so a wiring-only follow-up slice left this one red on its own.
Non-goals
Does not follow a wrapper more than one level deep, and cannot see inside a compiled binary. Code handed to a non-shell interpreter counts as data, so input driven from inside a Python or Node program is a known gap. Does not police the Write or Edit tools: authoring a driver is allowed, running it is what needs a window. Lock and idle detection is macOS-only; elsewhere only the marker applies.
Test Plan
Test Plan
python3 -m unittest discover -s engine/hooks/ui-input-guard/tests— 21 tests, OK (the lock and idle probes take an injected platform, so the macOS branch is exercised on Linux CI too)PreToolUseBash call with exit 2python3 scripts/check_hook_test_coverage.py— OK (23 hooks)python3 scripts/check_no_new_comments.py --base origin/main— okRevert Plan
Revert Plan
git revert <sha>./install.sh, thenrm -rf ~/.claude/hooks/ui-input-guard🤖 Generated with Claude Code
https://claude.ai/code/session_01KU2pPKob4MJ1NqjsfTNyYJ