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
125 lines
7.5 KiB
Markdown
125 lines
7.5 KiB
Markdown
# 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](https://www.rfc-editor.org/rfc/rfc5802.html#section-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](https://www.rfc-editor.org/rfc/rfc7677.html#section-3): SHA-256
|
|
exchange used as a second fixed primary-spec transcript.
|
|
- [Stanza 12.22.1 registry record](https://registry.npmjs.org/stanza/12.22.1):
|
|
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](https://github.com/legastero/stanza/blob/master/src/Client.ts)
|
|
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.
|