You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Security
Windows: text could run as PowerShell code (GHSA-9ppf-38v8-h97v, high).
Clipboard writes (type_text, smart_type, copy_all_text and the restore
of the user's clipboard), app launches, window-title lookups and relaunch_with_cdp quoted values into PowerShell source, and the quoting
could be broken by other characters PowerShell treats as quotes, so text
from a document, a page or the clipboard could break out and run commands
with no confirmation. Values now reach PowerShell only as data: clipboard
text on stdin, names and titles as environment variables, and a window pid
only when it is an integer. Large clipboard writes, which failed on the
command-line length limit, work too. macOS and Linux were not affected.
Versions through 1.5.25 are affected. Reported by @Sauron-sol (CleanIssue).
Fixed
macOS: window focus names secure input as the cause (#267). While a
password field holds secure input, macOS sends keys and focus only to that
app, and a focus ended with a vague "focus went to Google Chrome" / UNKNOWN.
The focus read-back stays the assertion (a successful accessibility call is no
evidence); when it fails, clawdcursor now checks IsSecureEventInputEnabled()
and, if on, finds the holder (kCGSSessionSecureInputPID via ioreg) and
returns a typed SECURE_INPUT result: "secure input is on (held by , pid N)
... Close or leave the password field in , then try again", with a pause_for_user next step. If the check cannot answer, the old message is
kept. macOS only; no open -b fallback.
A field below the fold is scrolled into view, not refused. On a long web form, accessibility find_field returned a field, then set_value / invoke on its {element_id, snapshot_id} failed with "element is off the active window", and smart_type with the field's label said "Could not find element". The ref check
took "outside the window's rectangle" to mean "in another window", but a page
element below the fold reports bounds past the window's edge. The element is
now scrolled into view with the platform's own call (Windows: UIA ScrollItemPattern.ScrollIntoView, else SetFocus; macOS: AXScrollToVisible;
Linux: AT-SPI Component.scroll_to), its bounds are read again, and the act
lands where it is now. It is still refused when it belongs to another window of
the app, when the platform cannot scroll, or when the scroll leaves it out of
view, and the error says which ("could not be scrolled into view (...)",
"scrolled but still not visible"). Scrolling sends no input and does not change
the window the agent is bound to (the active window is read again afterwards and
the act is refused if its handle, title or bounds differ); a stopped session does
not scroll. The platform looks only in the active window and picks the element
nearest the last-seen bounds, refusing when several share the name; the result is
then checked to be the referenced element (name, role kind, size). A scroll moves
every other element in the snapshot, so the snapshot is invalidated and the next
ref must be compiled afresh. Window titles and element names in these errors are
wrapped as untrusted screen content. smart_type with a target now also looks the field up in the compiled UI the
way find_field does (a field's label need not be its accessibility name) and
scrolls it in. Verified live on Windows 11 / Edge; the macOS and Linux calls are
unit-tested but still need a run on a real Mac and a real Linux desktop.
Added
The pause prompt is now a card: choices and a text box. Agents asked their
questions in their own chat while the user was looking at the screen (a yes/no on a
YC application had to be typed). pause_for_user takes choices (2-6 short options,
at most 40 characters each, de-duplicated: one button each) and/or input
({placeholder?, multiline?}: a text box with "Don't type passwords here"), and
returns {status:"replied", choice:"<exact option text>"} or {status:"replied", reply}. Bad values are rejected with the limit named; done_when cannot be combined
with a question. Resume / End task are unchanged, and a pause without choices / input looks and behaves as before. The overlays print BANNER_CHOICE <index>
(the text is looked up by the daemon, never taken from the overlay); the card reaches
them as JSON in CLAWD_BANNER_CHOICES / CLAWD_BANNER_INPUT. Windows and macOS show
the text box on the card; on Linux the pill cannot take the keyboard, so the
button reads "Type an answer" and opens the box. Only the user on screen can choose
(an agent's resume_task stays unverified), and a choice is never a safety approval:
Send / Delete / Pay confirmations are decided by the safety layer alone.
The MCP instructions, the pause_for_user description, the skill and llms.txt say
it plainly: while an agent is driving the desktop the user is watching the screen,
not its chat, so it should ask on the pause card (with choices when there are
options) rather than in its own chat.
Changed
A redesigned pill that says what the agent is doing. The running pill read
"desktop control in progress - double-click to stop" behind a red dot that looked
like an error, and a wait looked the same as finished work. It now shows an amber
dot, the current action and app ("Typing in Edge", "Opening a page"), the time since
it appeared, and a Stop button (a double-click anywhere still stops). Each guarded
input names its method once it passed the foreground and stop checks, and the
daemon sends the label as one ACTIVITY <text> line on the pill's stdin when it
changes; a refused input names nothing. The app is named only for keys, typing and
the pointer, which read the window in front first. The pause card has the same
look with a blue outline, "waiting for you" and the app, and one full-width row per
choice. Answers, focus handling and the stdout lines are unchanged on all three
overlays.