Skip to content

Strip unreadable and oddly-spaced candidates from the offer under Local networks - #874

Merged
nedtwigg merged 4 commits into
mainfrom
fix/local-networks-candidate-parse
Oct 1, 2026
Merged

nedtwigg merged 4 commits into
mainfrom
fix/local-networks-candidate-parse

Conversation

@dormouse-bot

@dormouse-bot dormouse-bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Under Local networks, the Burrow could apply a phone's offer that still carried a candidate outside the allowed networks. keepAllowed in lib/src/host/remote/local-networks.ts matched candidates with a single-space regex and split lines only on CRLF, keeping every line the regex missed. A candidate with a doubled space or a tab before its address, or one placed after a bare LF or CR inside a CRLF SDP, passed through unfiltered; the nightly audit verified that node-datachannel 0.33.4 accepts such lines in setRemoteDescription (#873).

The filter now splits lines on any of CRLF, LF, or CR, and fields on the C-locale whitespace libdatachannel's parser splits on (space, tab, vertical tab, form feed), not JavaScript's wider \s, so a non-ASCII space such as U+00A0 can't make the two parsers read different addresses. It drops any candidate line whose address is off the allowed networks or missing, and writes a c= line it cannot read as 0.0.0.0. Well-formed SDP filters exactly as before. The selected-pair check still runs as the backstop, so this closes the "offer it applies keeps a candidate outside them" clause of the security-remote.md FAIL IF rather than an open path.

The new case in local-networks.test.ts covers a doubled space, a tab, a bare LF, a bare CR, a whitespace-mangled c= line, a truncated candidate, and a foundation joined by U+00A0. It failed before the change and passes after. remote-network.md's offer-stripping rule now names unreadable candidates.

This settles one of the three FAILs in #873. The loopback-lint coverage gap and the installers' ts ip -4 | head -1 remain open there.

Refs #873 — automated triage

…al networks

The offer filter matched candidates with a single-space regex and split
lines only on CRLF, so a candidate with a doubled space or tab before its
address, or one after a bare LF or CR, kept its off-network address and
reached the native stack, which parses it.

Refs #873
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: c05a5d5
Status: ✅  Deploy successful!
Preview URL: https://e1b8fb46.mouseterm.pages.dev
Branch Preview URL: https://fix-local-networks-candidate.mouseterm.pages.dev

View logs

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field split still disagrees with the native parser on what counts as whitespace, so the doc comment's "no line the native parser reads as a candidate escapes this one" doesn't hold yet. JavaScript's \s matches Unicode whitespace such as U+00A0, while libdatachannel's Candidate::parse reads fields with std::istringstream >>, which splits only on C-locale isspace (space, \t, \n, \v, \f, \r). A foundation carrying NBSPs, such as a=candidate:x y z w 192.168.86.23 1 udp 2113937151 203.0.113.7 51234 typ host, gives this filter fields[4] === '192.168.86.23' and keeps the line, while libdatachannel reads the whole NBSP run as the foundation and 203.0.113.7 as the address. I read this in libdatachannel's source but didn't run it against node-datachannel, so whether libjuice then accepts the non-ASCII foundation is unconfirmed. The selected-pair check still backstops it either way. Splitting on the C set makes both parsers find the same fields. I'll push that change with a test case.

Comment thread lib/src/host/remote/local-networks.ts Outdated
…vaScript's \s

libdatachannel reads candidate fields with std::istringstream, which splits
only on C-locale whitespace. JavaScript's \s also matches U+00A0 and other
Unicode spaces, so a foundation carrying them shifted the field this filter
read as the address away from the one the native stack applies.

@nedtwigg nedtwigg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the C-locale field splitting, mixed line-ending normalization, malformed-candidate refusal, and NBSP regression. Resolved the test conflict by preserving both hardening and public-address diagnostics, restoring the diagnostic parser constant. Local tests/typecheck and fresh CI/bot review passed; the previous whitespace finding is resolved. Argos WebKit was reviewed and approved by nedtwigg, and both Argos browsers are green.

@nedtwigg
nedtwigg merged commit 139368c into main Oct 1, 2026
11 checks passed
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.

2 participants