Skip to content

馃殌 Release BOSS 9.5.5

Choose a tag to compare

@github-actions github-actions released this 29 Aug 07:04
· 93 commits to main since this release

BOSS v9.5.5

Release Date: 2026-08-29

One change. Opening a link in a new tab - cmd+click, or a target="_blank" button - could land on the page's own analytics beacon instead of the link, because the engine-wide POST capture was allowed to decide the destination and a page's telemetry ping usually fires first. The navigation is now the authority, a capture can only ever contribute a body, and the injected cmd+click handler is restricted to the links it is safe to adopt.

Highlights

  • A page's telemetry endpoint could become the tab. Two real cases caught it: a tab on internal-analytics.odoo.com/api/event titled "New Tab", and one on collector.github.com/github/collect titled "Collector". Both are POST-only beacon endpoints that appear in no page's markup, so nothing the user clicked could have produced them (#281)
  • The destination was being recovered from the wrong place. CreatePopupCallback is handed the popup's target URL and threw it away, so the handler subscribed to LoadStarted and re-read popupBrowser.url() - but LoadStarted carries no URL, so a navigation that had not committed yet never resolved at all and the handler sat out its full 3s timeout with the popup live and running the page's scripts (#281)
  • The three paths that can open a link now agree on what may become a tab. The adopted popup, the injected cmd+click handler and the fluck-browser plugin's middle-click resolver are all http(s) only, so javascript:, mailto:, file:, blob:, data: and about:blank#blocked stay with the page (#281)
  • The cmd+click script is tested by running it, not by grepping it. An SVG anchor's href is an SVGAnimatedString, so the unguarded handler opened a tab on the literal [object SVGAnimatedString] - a bug no amount of reading the script reveals (#281)

Bug Fixes

  • browser: an adopted popup's destination comes from its navigation, with the URL Chromium stated at creation time as the fallback for a popup that never started one. popupDestination is a pure function so it can be tested at all - no test can construct a BrowserHandleImpl - and reverting it fails the two tests named for the beacon URLs above (#281)
  • browser: the POST capture can only contribute a body, and only when it describes the request actually being navigated to. It is an engine-wide BeforeSendUploadDataCallback that claimed any request from the popup carrying a body, so an XHR, a CSP report or a sendBeacon ping from the popup's own page qualified and the first to fire won. It now claims MAIN_FRAME requests only (#281)
  • browser: NavigationStarted replaces LoadStarted as the source of the URL, since it carries one on the event - but it is not a superset of what it replaced. Its subscription is installed after the show request and JxBrowser does not replay to a late subscriber, so LoadStarted is kept alongside it, plus one direct re-read after subscribing (#281)
  • browser: a cmd+clicked PDF no longer opens a tab that re-triggers its own download. The legacy handler gated on FluckEngine.isActiveDownload; this path never did, and got away with it only because LoadStarted never fires for a download so no URL ever resolved. NavigationStarted does fire, so the gate came back, with the notifyTabOpened handshake so a redirect that turns into a file can still be undone (#281)
  • browser: the popup-target FIFO no longer desyncs by design. record skipped an unusable target while claim always popped, so window.open('') followed by a cmd+click handed popup 1 the URL of link B. PopupTargetQueue records every create and filters at claim (#281)
  • browser: a form posting to /print#page2 keeps its body. Chromium does not send the fragment to the network, so that submission reaches the upload callback as /print, and demanding an exact URL match silently downgraded it to a GET. Fragments are compared away (#281)
  • browser: POST capture is keyed by Engine rather than a process-wide uploadCallbackInstalled boolean. The Engine FluckEngine builds to recover a wedged renderer never got the callback, so capture stayed silently dead after a renderer recovery (#281)
  • browser: a popup that dies between the show request and our subscription no longer leaks. It threw out of the callback with its capture entry installed and no coroutine to remove it - a permanent strong reference to a dead Browser in a process-wide map (#281)
  • browser: the injected cmd+click handler hijacks the click before the page sees it, and is now guarded: primary button only, not an already-cancelled click, not a download anchor, http(s) only. An SVG anchor's href is read correctly rather than stringified (#281)

Improvements

  • browser: popup URLs are logged through LogSanitizer.maskUriParams, matching the rest of the file. The motivating workload is an EMR whose print URLs carry patient identifiers in the query string (#281)
  • browser: PopupTargetQueue's TTL is 2s, down from the previous 10s. Create and show are microseconds apart, and every millisecond in that window is time for an orphaned create to mispair with the next popup. The queue is bounded too, and documents that dropping the oldest past maxEntries knowingly abandons the pairing rather than leaving a reader to assume the FIFO guarantee is universal (#281)
  • browser: the cmd+click handler's KDoc no longer claims defaultPrevented tells us the page cancelled the click. It cannot - the listener is on the capture phase, so the page's handlers have not run yet (#281)
  • tests: 19 tests across three classes, all verified by reverting. PopupDestinationTest fails with the two beacon URLs from the field, PopupTargetQueueTest with the off-by-one misroute, and deleting the cmd+click protocol guard fails six cases in scripts/test/test-cmd-click.js (#281)
  • ci: node scripts/test/test-cmd-click.js runs in build.yml, reusing the harness test-browser-collector.js and test-find-key-probe.js already established - read the JS out of the Kotlin string and execute it under vm against a fake DOM. The grep test it replaces pinned the spelling rather than the behaviour: rewriting event.button !== 0 as 0 !== event.button failed the old test while changing nothing, and any guard reworded rather than removed passed it (#281)

Known Limitations

  • The FIFO pairing stops at maxEntries. A page opening popups faster than they are claimed drops the oldest entries, and every later popup shifts by one. Only the fallback destination is affected - the navigation still decides - and the alternative is unbounded growth (#281)
  • A popup with no resolvable destination is dropped. That is deliberate: sending it somewhere arbitrary is what this change exists to stop (#281)

馃摝 Downloads

Platform Architecture Package
macOS Universal (Apple Silicon + Intel) BOSS-9.5.5-Universal.dmg
Windows x64 BOSS-9.5.5.msi
Windows ARM64 BOSS-9.5.5-arm64.msi
Linux DEB AMD64 (x86_64) BOSS-9.5.5-amd64.deb
Linux DEB ARM64 (aarch64) BOSS-9.5.5-arm64.deb
Linux RPM AMD64 (x86_64) BOSS-9.5.5-amd64.rpm
Linux RPM ARM64 (aarch64) BOSS-9.5.5-arm64.rpm
Linux JAR AMD64 (x86_64) BOSS-9.5.5-amd64.jar
Linux JAR ARM64 (aarch64) BOSS-9.5.5-arm64.jar

Always latest - newest stable release, resolved server-side, so these stay
correct in a bookmark and need no API key:

macOS DMGWindows x64Windows ARM64Linux DEB amd64Linux DEB arm64Linux RPM amd64Linux RPM arm64Linux JAR amd64Linux JAR arm64

Release metadata - version, every asset, sha256 checksums - is at ?app=boss.


Full Changelog: v9.5.4...v9.5.5