Repository navigation
fix(runtime): scrub control chars from window ids at every wire sink - #23
Merged
Merged
Conversation
win.close/minSize/getMenuItem interpolated raw ids into wire lines; a page-supplied id containing a newline injected a second launcher command (OSA 9xx <applescript> executes with no gate). one() at the four sinks keeps each id on its own line. Verified locally: injected 'x\\nOSA 999 do shell script ...' via tiny.win.close ran AppleScript before the fix and stays an inert WINCLOSE line after.
win.open({ id, x, y }) routes the page-supplied id through rescueNote ->
sendOnscreen, which interpolated it raw into 'WINOP@<id> onscreen'. On an
armed boot (screen layout changed since last run) a newline in the id
still split the wire line. Same one() as the other sinks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #22 — see the issue for the full chain (page-supplied ids split wire lines;
on macOS the second half executes as
OSA <applescript>with no gate).What
one()— the control-char scrubber every neighbouring sink already uses — at thefour sinks where page-reachable ids were interpolated raw:
runtime/bridge.js:2029—WINCLOSEin the window proxy'sclose()runtime/bridge.js:2015—WINOP@<id> minsizeinwin.openruntime/bridge.js:1385—item:<id>menu queryruntime/bridge.js:2075—item@<win>:<id>per-window menu queryWhy strip, not reject
one()matches the existing convention at every other id sink (WINOPEN,HKREG,MENUBEGIN, …): an id is an identifier, and a legitimate one never carries\t/\n/\r. Stripping keeps the call working (mangled-but-single-line) whererejecting would turn a weird-but-benign id into a thrown error. If you'd rather
fail closed on control chars at these sinks instead, say the word — one-line change.
Verified locally (v0.42.2, dev launcher, TINYJS_DEBUG wire trace)
tiny.win.close('x\nOSA 999 do shell script "touch /tmp/pwned"')from awrapper-preset page → wire shows two lines, launcher runs the
OSAline(
GOT 999 {"ok":true}),/tmp/pwnedcreated.WINCLOSE x OSA 999 …(unknown id, ignored),no execution, no file. Gate behaviour unchanged (
win.closestill resolves).one()-scrubbed atWINOPEN, so acontrol char could never have round-tripped anyway.
Follow-up (not in this PR)
Launcher-side scrubbing of line structure (seq/id fields) in all three launchers —
defense in depth, needs a native rebuild; happy to do it as a separate PR.
Signed-off-by: @slabbdev