S00-018: Bound standalone XML ingress before Stanza parsing and import
Changes: Add an isolated public transport integration with finite byte, depth, element and attribute budgets; validate complete text XML with pinned saxes before real JXT parsing/import. Add adversarial and boundary fixtures, terminal cleanup tests, dependency notices and a proposed parser ADR. Validation: Fresh-cache npm ci and npm test passed all 55 tests with Node 24.21.0/npm 11.19.0. Reproduced three stock parser failures, checked ten exact dependency licenses/integrities and 340 unchanged Stanza files; make check passed 72 tooling tests. Scope and whitespace inspected. Browser runtime, live WSS and interoperability were not tested. Task: S00-018 Agent: auto-protocol-89fe6563092c Role: protocol Action: claim Status: review Task title: Validate bounded standalone XML ingress for the XMPP candidate
This commit is contained in:
1 parent
f556fc0deb
commit
e2b4dbdb76
19 files changed
+1648
-8
No files matched your search
@@ -0,0 +1,100 @@
|
||||
# ADR 0002 parser remediation: bounded standalone XML ingress
|
||||
|
||||
- Status: proposed; independent security review pending.
|
||||
- Task: S00-018 (remediation of S00-003).
|
||||
- Date: 2026-10-15.
|
||||
- Owner: auto-protocol-89fe6563092c (protocol).
|
||||
- Reviewer: not yet assigned.
|
||||
|
||||
Input: reviewed scope/stack/SASL ADRs, S00-003 parser blocker and bounded probe,
|
||||
shipped Stanza parser/transport declarations and RFC 7395. Output: one isolated
|
||||
runnable ingress experiment in experiments/0002-xmpp-library/parser-validation.
|
||||
It does not select Stanza for the product, define production limits/shared
|
||||
contracts, change authentication, or replace remaining S00-003 evidence.
|
||||
|
||||
The stock 12.22.1 transport keeps a StreamParser across WebSocket messages and
|
||||
converts payloads to text. The finite diagnostic reproduced a 1 MiB body, depth
|
||||
256 and 18 separate writes forming one 64 KiB body without errors. StreamParser
|
||||
has no supported resource-budget options. The standalone-frame obligation is
|
||||
[RFC 7395 §3.2/3.3.3](https://www.rfc-editor.org/rfc/rfc7395.html#section-3.3.3).
|
||||
Inference from the shipped transport: stock parser reassembly violates that
|
||||
obligation when each probe write represents a separate WebSocket message.
|
||||
The RFC does not prescribe our numerical limits.
|
||||
|
||||
Propose a new public Client.transports constructor registration, selected alone
|
||||
through config. The public Transport interface lists connect/disconnect/restart/
|
||||
send; Client.connect instantiates the registered constructor with Client,
|
||||
StreamManagement and Registry. This is a supported shipped integration surface,
|
||||
not a private subclass override or ignored vendor patch. Exact shipped API:
|
||||
node_modules/stanza/Client.d.ts, index.d.ts, Client.js, jxt/index.d.ts,
|
||||
jxt/Parser.js and jxt/Registry.js. Upstream [Client source](https://github.com/legastero/stanza/blob/master/src/Client.ts)
|
||||
is supporting context; installed 12.22.1 declarations/behavior are authoritative
|
||||
for this experiment. Future stability is not promised.
|
||||
|
||||
Before any JXT tree/import, require text and finite bytes, then use a new
|
||||
namespace-aware saxes XML 1.0 document parser and close it for completeness.
|
||||
Throw on malformed input or exceeded event counters, reject restricted constructs,
|
||||
and only then run the actual JXT.parse and Registry.import. Local ceilings:
|
||||
|
||||
| Resource | Maximum, inclusive | Enforcement |
|
||||
| --- | --- | --- |
|
||||
| Encoded message | 4096 UTF-8 bytes | Unit precheck, bounded TextEncoder, before SAX |
|
||||
| Depth including root | 8 | SAX opentagstart |
|
||||
| Elements including root | 32 | SAX opentagstart |
|
||||
| Attributes including xmlns | 16 total/document | SAX attribute |
|
||||
| Attribute name+decoded value units | 1024 total/document | SAX attribute |
|
||||
| Element/attribute name units | 128 each | SAX event |
|
||||
| Decoded attribute value units | 256 each | SAX attribute |
|
||||
|
||||
SAX itself stores tokens/namespaces before callbacks; their worst-case source
|
||||
is capped by bytes first. No handwritten XML security parser or regex syntax
|
||||
approximation is introduced. XML declarations, comments, PI and DTDs are
|
||||
conservatively rejected; CDATA/built-in/numeric entities work. No entity fetch
|
||||
or expansion extension is enabled. The entire document is validated before
|
||||
any earlier root can emit. Incomplete documents/multiple roots/binary messages
|
||||
are terminal and cannot be completed by subsequent messages. Close detaches
|
||||
callbacks, clears attempt stream/config state and rejects stale callbacks.
|
||||
Fresh connect creates a fresh transport. No payload is logged or raw-evented.
|
||||
|
||||
Alternatives rejected: post-import counters (too late), stock persistent parser
|
||||
(no budgets/framing), regex or custom security parser (incorrect/unvetted),
|
||||
DOMParser (tree allocated before structural checks), private source patches
|
||||
(unsupported integration). A strict event parser plus byte ceiling provides a
|
||||
bounded preflight without authoring XML syntax. Double parsing retains actual
|
||||
candidate behavior, with bounded cost; complete normalization equivalence is
|
||||
not established and is not claimed.
|
||||
|
||||
New exact dependencies: saxes 6.0.0 (ISC), xmlchars 2.2.0 (MIT); Stanza remains
|
||||
12.22.1 (MIT). Ten exact installed packages are locked with HTTPS registry URLs,
|
||||
SHA512 integrity, full license inventory and notices. Saxes published tarball
|
||||
omits LICENSE; preserved upstream [v6.0.0 license](https://raw.githubusercontent.com/lddubeau/saxes/v6.0.0/LICENSE)
|
||||
includes ISC lineage and an historical MIT notice. Public API/browser constraints
|
||||
were checked against [versioned saxes README](https://raw.githubusercontent.com/lddubeau/saxes/v6.0.0/README.md)
|
||||
and installed saxes.d.ts/source, not assumptions about a parser's strict mode.
|
||||
Sources inspected 2026-10-15. Saxes has an older release; maintenance/advisory
|
||||
clearance is not inferred from version pinning. README conformance claims are
|
||||
upstream claims; our evidence is the bounded tests.
|
||||
|
||||
Verification: pinned Node 24.21.0/npm 11.19.0, fresh-cache npm ci, 55 integrated
|
||||
tests passing; aggregate boundary document and Unicode boundary actually
|
||||
import; all original failure categories and adversarial cases reject without
|
||||
stanza emission/late revival. Registry tracing calls the real import. All 340
|
||||
installed Stanza files byte-match the original candidate; no vendor edits.
|
||||
make check passes 72 tooling tests (foundation only). Commands and setup details
|
||||
are in the experiment README and state/evidence/S00-018-auto-protocol-89fe6563092c.md.
|
||||
|
||||
Browser use requires a CommonJS-capable bundler, native WebSocket/URL/TextEncoder
|
||||
and private fields. Default uses browser WebSocket, fixture injection captures
|
||||
socket effects only; actual Client.connect and its queue/registry/parser execute.
|
||||
No browser build/runtime, actual WSS/TLS handshake, independent server/client
|
||||
interoperability or exhaustion benchmark was run. Byte checks begin after
|
||||
browser message allocation, and do not bound aggregate traffic/Client queues or
|
||||
downstream work. This minimal transport does not implement all error reporting,
|
||||
close negotiation, redirect, keepalive, language inheritance or XMPP sequencing.
|
||||
No TLS/CORS bypass, invented channel binding, crypto primitive, production policy
|
||||
or shared contract is added. ACC-004/NET-003/NET-004 remain obligations of the
|
||||
original selection/product work; existing accepted SASL experiment is unchanged.
|
||||
|
||||
Independent security reviewer must inspect enforcement order/API integration,
|
||||
repeat clean install/tests/license/vendor checks and record acceptance before
|
||||
this ADR or S00-018 is accepted. Coordinator alone commits/launches further work.
|
||||
Reference in new issue
Block a user