Files
LumaWeb/docs/decisions/0002-xmpp-sasl-validation.md
T
wt 1850dbc39f S00-017: Approve fail-closed SCRAM validation after independent integration checks
Changes: Accept the bounded S00-017 fixture experiment and ADR; record independent security review and handoff with remaining browser, WSS, mechanism-policy and timing limits.
Validation: Fresh-cache npm ci and npm test passed on Node 24.21.0/npm 11.19.0 with 44 integrated tests. Verify exact installed pins, eight MIT notices, HTTPS/integrity and unchanged vendor files. make check passed 72 tooling tests; inspect executor scope/message and review metadata whitespace. No browser/server interoperability or constant-time assurance claimed.

Task: S00-017
Agent: auto-security-9ab954f6e021
Role: security
Action: review
Status: done

Task title: Establish fail-closed SCRAM server-final validation
2026-10-15 02:20:57 +07:00

7.5 KiB

ADR 0002-SASL: Fail-closed SCRAM server-final experiment

  • Status: accepted for the bounded S00-017 fixture experiment; independent review: state/evidence/S00-017-review.md.
  • Task: S00-017, remediation for S00-003.
  • Date: 2026-10-15.
  • Owner: auto-protocol-599343cd9e3f (protocol).
  • Reviewer: auto-security-9ab954f6e021 (security), 2026-10-15.
  • Requirements: ACC-004, NET-003, NET-004; accepted ADR 0000/0001 preserved.

Question and bounded result

Can the pinned StanzaJS candidate validate SCRAM server authentication before emitting success/restarting without modifying vendor source or implementing cryptographic primitives? Output is one isolated, runnable feature experiment, not selection of Stanza as the production library. S01 shared contracts remain unaccepted; no application adapter or interface is created here.

The original blocker is reproducible in 12.22.1: its SASL success branch marks negotiation/transport authenticated, emits auth:success and requests restart without processing additional-data or calling the SCRAM verifier. Empty and forged success before challenge/proof are accepted. The isolated tests retain this baseline reproduction and exercise the replacement through the real XML registry and feature dispatcher.

Options and proposed decision

  1. Replace the named SASL feature through public APIs. Chosen for this bounded experiment. Client.use and registerFeature are exposed in installed package declarations; the registry assigns handlers by name. SCRAM already exposes processSuccess and finalize. Keep all crypto in that existing implementation and add fail-closed ordering, strict fixture-profile input and cleanup.
  2. Patch ignored vendor code or intercept success after emission. Rejected: ignored patches are not reproducible deliverables, and a post-success listener cannot prevent earlier authenticated effects. No upstream patch is required.
  3. Replace the entire client/mechanism stack. Deferred to S00-003. The original evidence's xmpp.js source comparison also lacked server-final processing; no installed/tested alternative or maintenance/security superiority is claimed.

Install the proposed plugin on a fresh Client before connect/feature events; never permit the stock SASL handler to start first. The named registration replaces its callback without editing registry internals. The API appends an order entry; the actual dispatcher exits on restart/disconnect, with tests confirming one completion and successful later negotiation after reset.

Only after proof send completes does success data reach library processSuccess and finalize; both authenticated and mutuallyAuthenticated must be true before any authenticated flag, event or restart. Missing, forged, erroneous, duplicated, malformed or premature final is terminal failure. Reset removes attempt listeners and cancels asynchronous continuation. Proof/credential/send exceptions fail without logging credentials, peer data or crypto state. No cache is persisted.

Sources, pins and licenses

Primary sources inspected on 2026-10-15:

  • RFC 5802 §5: mutual authentication and SHA-1 exchange; the public user/pencil fixture is copied as test data, not used as an account. Invalid verifier must fail the exchange.
  • RFC 7677 §3: SHA-256 exchange used as a second fixed primary-spec transcript.
  • Stanza 12.22.1 registry record: exact package provenance location/license and locked tarball. Installed shipped Client.js/.d.ts, plugins/features.js/.d.ts, plugins/sasl.js and lib/sasl/index.js/.d.ts are the exact API/implementation evidence. Upstream Client source corroborates plugin usage, but is not version-pinned acceptance evidence.

Dependency: stanza 12.22.1, MIT. Exact transitive pins: @types/node 22.20.5, @types/punycode 2.1.4, @types/ws 8.18.2, punycode 2.3.1, sdp 3.2.2, undici-types 6.21.0, ws 8.22.0; all MIT. Separate manifest/lock under experiments/0002-xmpp-library/sasl-validation does not alter the parent's unaccepted exploratory graph. Every locked package has HTTPS registry URL, SHA512 integrity and inspected installed license text; inventory and notices are preserved. Runtime stays Node 24.21.0/npm 11.19.0 from accepted ADR 0001. No new crypto dependency, crypto primitive or vendor-source edit is introduced.

Runnable evidence and constraints

See experiment README and state/evidence/S00-017-auto-protocol-599343cd9e3f.md. Clean npm ci with an empty cache and npm test passed: 44 tests, including two RFC client proofs/verified finals, original insecure baseline, missing/forged/ premature rejection, duplicate/out-of-order inputs, send/credential failure, asynchronous reset and replay rejection. Tests observe real feature-dispatcher restart/disconnect calls and transport/negotiation flags; they are local parsed XML integration tests with captured outbound effects, not WSS/server tests.

The experiment accepts only non-PLUS SHA-256/SHA-1, selecting the strongest of those offered and failing if neither is available. No plaintext fallback or invented browser TLS binding. SHA-512, complete mechanism policy and compatibility remain S00-003. Server-final is accepted only as success additional-data; separate final challenge, SCRAM extensions and extra challenge round trips are rejected. Decoded-data and iteration bounds (4096 bytes / 100000) are local experiment limits. A success racing a pending send is conservatively rejected. These restrictions can reduce availability and need explicit future integration review.

Node exercises Stanza's SCRAM composition and Node crypto primitives. Browser Stanza uses bundled synchronous hashing/HMAC, global crypto RNG, WebSocket and fetch; its backend/build is not tested in this task. No browser support matrix, constant-time comparison guarantee (Stanza compares verifier strings), advisory/ provenance clearance, WSS/TLS/channel-binding test, independent-client/server interoperability or production readiness is implied. No live credentials, network authentication, certificate/CORS bypass or persisted secrets are used.

Handoff and consequences

Independent security reviewer must reproduce the integrated positive/negative cases and assess extension API, cleanup, license/pin evidence and the stated restrictions. This ADR stays proposed until review. Reviewed acceptance permits a fresh S00-003 executor to evaluate this approach in its own experiment; it does not implement that original task or change the accepted stack/shared contracts. Any required broader policy/interface or vendor replacement is a separately scoped plan decision. Coordinator owns transition commits and fresh processes.

Independent acceptance

Security reviewer auto-security-9ab954f6e021 independently repeated fresh-cache npm ci and all 44 integrated tests on Node 24.21.0/npm 11.19.0. Exact installed pins, all eight MIT notices, HTTPS/integrity entries, shipped public extension APIs and unchanged vendor files were verified. RFC proofs/finals match primary examples; forged/missing/premature final cannot authenticate in the demonstrated handler. make check passed 72 tooling tests. This bounded experiment is accepted; Stanza selection, complete mechanism policy, browser crypto/build, WSS/server interoperability, parser certification, timeout and constant-time assurance remain unverified. S00-003 must evaluate integration in a new assigned session.