Skip to content

fix(use_computer): pass application name as a subprocess argument - #519

Draft
yonib05 wants to merge 3 commits into
strands-agents:mainfrom
yonib05:fix/use-computer-subprocess-args
Draft

fix(use_computer): pass application name as a subprocess argument#519
yonib05 wants to merge 3 commits into
strands-agents:mainfrom
yonib05:fix/use-computer-subprocess-args

Conversation

@yonib05

@yonib05 yonib05 commented Jun 27, 2026

Copy link
Copy Markdown
Member

open_application and focus_application built their subprocess command or script by string-interpolating the application name. This changes them to pass the name as data rather than as part of the command text, which also avoids quoting issues for names with spaces or punctuation.

  • open_application (Windows): use subprocess.run(["cmd", "/c", "start", "", name], shell=False) instead of subprocess.run(f"start {name}", shell=True).
  • focus_application (macOS): the AppleScript body is now constant (on run argv ... item 1 of argv ...) and the name is passed as an osascript argv item.
  • focus_application (Windows): PowerShell uses AppActivate($args[0]) with the name passed as an argument.
  • Names not in the built-in mapping are validated against a printable-name allowlist before any subprocess call.

Adds regression tests covering the new argument forms and rejected names. Full use_computer suite passes; ruff format/ruff check clean.

Pass the application name to the platform launch and focus mechanisms as a
separate argument rather than interpolating it into the command string or
script source, so the name is always treated as data.

- open_application: use the list form ["cmd", "/c", "start", "", name] with
  shell=False on Windows instead of a formatted "start <name>" string.
- focus_application: pass the name to osascript via "on run argv" and to
  PowerShell via $args[0], keeping the script body constant.
- Validate that names not in the known mapping are plain, printable names.

Adds regression tests covering the argument forms and name validation.
The application name is passed to launch and focus mechanisms as a
separate argument and is never interpolated into a shell command or
AppleScript/PowerShell body, so normal printable names cannot be parsed
as code. The previous allowlist regex rejected legitimate names such as
'C++ Builder' and names containing colons or other punctuation, while
still permitting some punctuation, so it added little value at the cost
of a breaking change.

Relax validation to reject only control characters and newlines as light
defense-in-depth, and keep regression tests asserting injection payloads
remain inert argv data.
@yonib05
yonib05 marked this pull request as draft June 29, 2026 21:46
…d.exe injection

The Windows open_application path launched apps with
subprocess.run(["cmd", "/c", "start", "", actual_app_name], shell=False).
Even with shell=False, subprocess builds the command line with list2cmdline,
which only quotes argv items containing whitespace. A spaceless payload such
as "notepad&whoami" therefore produced the command line
`cmd /c start "" notepad&whoami`, and cmd.exe reparsed '&' as a command
separator, allowing command injection. The _CONTROL_CHARS allowlist does not
block cmd metacharacters (& | < > ^ ( ) %).

Launch via os.startfile instead, which uses the shell association API directly
and never invokes cmd.exe, so metacharacters stay inert and the exact literal
name is used. Mapped-name behavior is unchanged, and focus_application (already
argv-safe) is untouched.

The prior injection test only used a spaced payload, which list2cmdline quotes,
masking the bug. Tests now assert os.startfile is called with the exact literal
name (including a spaceless "notepad&whoami" payload) and that cmd.exe is never
spawned.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant