Skip to content

v2.13.0 — tab-ownership hardening (three-pass audit)

Choose a tag to compare

@achiya-automation achiya-automation released this 14 Jun 15:23
· 5 commits to main since this release
a38017f

A full-codebase security/correctness pass closing the tab-ownership enforcement gaps end to end (third audit pass, 2026-06-11).

Tab safety

  • ~20 page-mutating tools called the engine directly with no ownership guard (cookies, all storage writers, import_storage, drag, upload_file, paste_image, select_option, react_select_set, mock_route, throttle_network, override_geolocation, handle_dialog, resize) — only click/fill were guarded. All now call _assertTabOwnership() first.
  • safari_run_script enforces ownership per step while the batch runs. The single pre-flight check was defeatable: evaluate was exempt, and a mid-batch switchTab/navigate could move to the user's tab before a click ran. A refused step now aborts the whole batch.
  • _isURLOwned required no path-segment boundary — owning /org also "owned" /org-evil on the same origin. Matching now requires a real / boundary; semantics extracted to ownership-match.js and locked by a unit suite (incl. the /org vs /org-evil case).
  • Ownership TTL enforced on use (was rewriting every entry's timestamp to now on each save → 30-min expiry never fired, leaking ownership across sessions).
  • Extension: owned-tab state survives MV3 service-worker restarts (storage.session) — a restart used to wipe the in-memory map and silently re-enable the permissive "no tabs owned yet" path. Also fixes navigate_and_read cache staleness, cross-window retargeting, and a close_tab last-tab TOCTOU.

Robustness

  • Swift daemon: GCD thread-leak respawn after 8 stuck executions, autoreleasepool per command, clean exit(0) on stdin EOF, safe mouse-restore (no jump to 0,0).
  • Atomic owned-tabs.json writes (tmp + rename); bounded in-page console/network buffers; HTTP-bridge oversized-body parse fix; connect() re-entrancy lock; unguessable evaluate result key (crypto.randomUUID).

Correctness

  • safari_press_key sends W3C code values (Enter, ArrowUp, Digit1…) — fixes apps routing on event.code (Notion, Monaco, Google Docs).
  • Lexical fill dual-layer (JSON-then-JS) encoding; set_cookie/mock_route escaping via escJsSingleQuote(); /var/folders allowlist fix.

Tooling

  • npm test now runs the test/ unit suites (escaping + ownership) alongside the smoke test; engines.node >= 20.

Full detail in CHANGELOG.md.