Skip to content

fix(guard): let scripts print a sign-in link without being refused - #1140

Draft
sosidudku1 wants to merge 3 commits into
mainfrom
fix/ato-1353-browser-guard-print
Draft

sosidudku1 wants to merge 3 commits into
mainfrom
fix/ato-1353-browser-guard-print

Conversation

@sosidudku1

@sosidudku1 sosidudku1 commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

What

The browser-bypass guard reads the text of scripts the agent runs and refuses open https://…. A script that only prints a sign-in hint was refused at every approval level: Python print("… open https://…"), Node console.log(…), and shell echo/printf with more than one quoted argument.

Now string literals passed to print-only calls are blanked before the line rules run: print, sys.stdout/stderr.write, logging/logger calls, console.*, process.stdout/stderr.write, and echo/printf with several quoted arguments. Code inside f-string {…} and template ${…} is still scanned, and so are strings inside nested calls. Nothing is blanked when the output could be run. That is decided from the outer command line, including for script files read from disk: any pipe, a redirect to a file, $(…), backticks, <(…), eval or xargs on the line that runs the script turns blanking off. Nothing is blanked either when the text rebinds or wraps a print name (print = os.system, console.log = …execSync, a log object built from os.system, file= in a print call, setattr, __import__, Object.assign and similar), or mentions subprocess, popen, system, child_process, exec, spawn or eval. Unbalanced or odd text is left as is and judged as before. The scanner lives in the new printed-literals.ts.

Real launches are still refused: subprocess.run(["open", url]), os.system("open …"), child_process.exec, execSync("xdg-open …"), printed text piped into sh (also python3 prints.py | sh and node prints.js | sh, where the print is inside the script file), output redirected to a script, and print names rebound to an exec function.

Why

A sign-in helper that prints the link for the user to open is a normal thing for the agent to run and hand over.

Known gap

open "$(python3 x.py)" is not caught; that is the same on main (the lexer gives up on $( before reading the script).

Notes

  • browser-bypass.ts was 538 lines before this change and is 542 now; splitting it under 300 is left for a separate change.
  • The live scenario L14 fixture is not on main; nothing changed there.

Tests

browser-bypass.test.ts CASES table: allowed print-only cases in shell, Python and Node; refused launch cases listed above, including the four print-rebinding lines and the script-file pipe and redirect cases (fixtures prints.py, prints.js).

Fixes ATO-1353 (also filed as ATO-1349).

Not yet checked on the second Mac.

The browser bypass check read the text of print-only calls as if it ran,
so python print("open https://..."), console.log(...), sys.stdout.write
and process.stdout.write were refused at every approval level (ATO-1349,
ATO-1353). String literals passed straight to these calls are now emptied
before the line rules run; strings inside nested calls, f-string and
template interpolations, and any output piped on to a runner are still
read. echo/printf with several quoted arguments are exempt too.
blankPrintedLiterals, the print-call pattern, the literal scanner and the
check for output that could be run now live in printed-literals.ts next
to browser-bypass.ts, which imports the one function it needs. No change
in behaviour.
…name is rebound

Two holes in the print-only exemption. A script file was blanked on its
own text, so python3 x.py | sh with print("open https://...") in x.py
passed: whether output stays on the terminal is now decided from the
outer command line (pipe, file redirect, substitution, eval, xargs) and
carried to script files read from disk. And print, console.log or log.info
rebound to os.system / execSync, or print(..., file=...) into a process,
were blanked like real prints: any rebinding, file= argument or mention of
subprocess, system, popen, child_process, exec, spawn or eval now leaves
the text as it was.

This branch has not been deployed

No deployments
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