Skip to content

Milestone 41: site isolation and browser-process storage - #1

Merged
protechnocrats merged 7 commits into
mainfrom
m41-site-isolation
Oct 23, 2026
Merged

protechnocrats merged 7 commits into
mainfrom
m41-site-isolation

Conversation

@protechnocrats

Copy link
Copy Markdown
Owner

A renderer now holds documents of one site (ADR 025). When a navigation lands on another site, the browser does not deliver it: the page moves to a fresh renderer, handed the response already fetched, behind the unchanged engine API. The old document stays shown until the new one commits; a failed navigation moves nothing.

A document is now named by the URL it landed on after redirects, not the one it asked for (M21's simplification). That URL becomes the page's current URL, names its origin, and is what NavigationCommitted reports, so a page redirected to another site keeps its script requests and storage.

localStorage is served by the browser process from the profile's store, through the page's own grant and only for origins the renderer loaded, so pages of one origin share it in process mode. The browser also enforces the network grant and withholds cross-origin responses a mislabelled request cannot use.

Sandboxes beyond Linux are not built (backlog). 1,209 tests pass (14 new).

Also cleans up stale documents: milestone notes that later work overturned are marked with when they were closed; commit hashes and a branch from the pre-squash history, which no longer resolve, are removed; CI status says what is verified (a remote exists, no run observed); and the webidl_parse/02_window fuzz seed is regenerated to match window.webidl.

protechnocrats and others added 7 commits October 22, 2026 20:40
A renderer now holds documents of one site (ADR 025). When a navigation
lands on another site, the browser does not deliver it: the page moves to
a fresh renderer, handed the response already fetched, behind the
unchanged engine API. The old document stays shown until the new one
commits; a failed navigation moves nothing.

A document is now named by the URL it landed on after redirects, not the
one it asked for (M21's simplification). That URL becomes the page's
current URL, names its origin, and is what NavigationCommitted reports, so
a page redirected to another site keeps its script requests and storage.

localStorage is served by the browser process from the profile's store,
through the page's own grant and only for origins the renderer loaded, so
pages of one origin share it in process mode. The browser also enforces
the network grant and withholds cross-origin responses a mislabelled
request cannot use.

Sandboxes beyond Linux are not built (backlog). 1,209 tests pass (14 new).

Also cleans up stale documents: milestone notes that later work
overturned are marked with when they were closed; commit hashes and a
branch from the pre-squash history, which no longer resolve, are removed;
CI status says what is verified (a remote exists, no run observed); and
the webidl_parse/02_window fuzz seed is regenerated to match
window.webidl.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cargo-fuzz defaults --target to the triple it was built for. The
prebuilt binary from taiki-e/install-action is static musl, so every
fuzz target failed to build (ASan is incompatible with static libc).
Pass the nightly toolchain's host triple explicitly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page thread publishes its tick and THEN calls the waker, and
update_blocking returns on the publish, so on a loaded runner the test
could read the counter before the wake. Poll with the usual deadline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- rustls 0.23.46, rustls-webpki 0.103.16, webpki-roots 1.0.10 fix
  RUSTSEC-2026-0346..0349, -0381 and -0382 (root and fuzz lockfiles).
- yoke-derive 0.8.3 was yanked; now 0.8.4.
- RUSTSEC-2026-0206 (rustybuzz unmaintained) accepted alongside the
  existing ttf-parser exception it depends on (ADR 009, ROADMAP §7).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6378d9a dropped the space after `--`, so the first libFuzzer flag was
passed to cargo-fuzz as `---max_total_time=60` and every target was
rejected at argument parsing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- images: a PNG header declaring billions of pixels made decode_png
  allocate the output buffer it described (~51 GB). png's Limits do
  not cover the caller's buffer; apply the shared pixel cap first.
- text: a `ttcf` header claiming 2^32-1 fonts tripped ttf-parser's
  length debug-assert. Refuse collections whose offset table does not
  fit in the file, before the parser (and in the directory scan).
- fuzz: js_script now collects the script heap after each input, as a
  page thread does; Boa's lazy GC read as a 1 MiB leak to libFuzzer.

Regression tests in both crates; both inputs added as seeds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- css_parser: a parent selector with an unclosed `(` hid its
  expansion's commas from the nested-selector count, so every nested
  level passed MAX_NESTED_SELECTORS while multiplying the selector text
  by its child count (5 KB of CSS -> ~800 MB, 12 s under ASan). Cap the
  expanded text too (64 KiB), sized before building so `&&&…` children
  are covered as well.
- images: zune-jpeg 0.4.21 debug-asserts when entropy data runs out
  mid-symbol (it saturates in release). 0.5 removed the assertion as a
  known fuzzer false positive; upgrade (ZCursor input, same limits).

Regression tests in both crates; both inputs added as seeds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@protechnocrats
protechnocrats merged commit a7983ad into main Oct 23, 2026
4 checks passed
protechnocrats added a commit that referenced this pull request Oct 24, 2026
* fix: refuse selectors with unclosed brackets, stop nesting invalid ones

The CSS nesting blow-up found by fuzzing (0b427ba) was capped, not fixed:
the selector parser accepted `a:not( .c0`, and nesting copied that text
into every child, where the unclosed `(` hid their commas from the
selector-count cap.

- A selector with an unclosed `(` or `[` (outside a string) is invalid;
  in CSS syntax the bracket would run on past the rule's `{`.
- A nested rule passes down only combined selectors that parse. An
  invalid one matches nothing, nor does anything nested under it.
- Both nested-selector caps report a new Guard::CssNestedSelectorsTooLarge
  instead of borrowing the @media depth guard.
- The regression test checks output instead of elapsed time.

The fuzz input now builds nothing past its first level; the 64 KiB text
cap stays for `&`-heavy children. 1,213 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: record the first CI runs and the libFuzzer findings

- AUDIT.md: a CI row (every PR job passes on PR #1; the nightly fuzz job
  has not passed yet), the five fuzz findings, three advisory exceptions
  (rustybuzz added), 1,213 tests; the "no CI run observed" gaps updated.
- M25: a "First CI runs" section: the two fuzz-smoke script fixes, the
  five bugs and their fixes, and why the first nightly run failed (it ran
  before PR #1 merged, on the script without the --target pin).
- ROADMAP: the font risk names both unmaintained crates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@protechnocrats
protechnocrats deleted the m41-site-isolation branch October 24, 2026 00:59
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