Changes: Preserve incomplete work and blocker metadata for S00-003. This checkpoint does not mark implementation accepted. Validation: Session ended with status blocked. Blocker: StanzaJS 12.22.1 SASL feature accepts missing/forged server-final without processSuccess/finalize, including success before challenge/proof. Safe SCRAM cannot be attested by S00-003 until this authentication boundary has a reviewed solution. Task: S00-003 Agent: auto-protocol-826aa6bc12ef Role: protocol Action: claim Status: blocked Task title: Проверить XMPP WSS/auth библиотеку
7.7 KiB
S00-003 blocked executor evidence
Agent: auto-protocol-826aa6bc12ef / protocol. Date: 2026-10-15 (local). Outcome: incomplete library evaluation; no library ADR accepted or proposed. Blocker: candidate SASL success paths do not establish SCRAM server authentication.
Inputs and scope
Read master_prompt, AGENTS, README, protocol/common roles, WEB_PROFILE, ARCHITECTURE, CONTRACTS, WORKFLOW, AUTOMATION, GIT_WORKFLOW, required TESTING and decisions/README; assigned resume/show/packet/card, exact ACC-004/NET-003/NET-004, accepted scope and stack ADRs, direct dependency executor/review evidence and handoffs. No previous S00-003 handoff existed in packet. S01 shared schemas are future work; none created. Input: accepted browser stack and exact auth/WSS requirements. Intended output: one library-selection ADR and focused runnable WSS/SCRAM/parser/extension spike. Acceptance remains incomplete.
Only source writes before discovering blocker: experiments/0002-xmpp-library/package.json and package-lock.json. These pin exploratory stanza 12.22.1 with accepted Node 24.21.0/npm 11.19.0. npm installed 8 packages. node_modules is ignored. The manifest is unfinished (test script points to tests not yet authored); no successful test suite, production adapter, or library selection is implied. Source edits stopped at blocker. Reports/issue/handoff are workflow metadata. No Git mutations, shared contracts, specs or app modules changed.
Commands/results
- python3 scripts/tasks.py resume --agent auto-protocol-826aa6bc12ef; show S00-003; packet S00-003 --agent auto-protocol-826aa6bc12ef: exit 0 each, correctly assigned in_progress, prerequisites done, no second claim.
- npm view stanza version license engines dependencies --json --cache /private/tmp/luma-xmpp-cache --fetch-retries=0 --fetch-timeout=15000 --registry=https://registry.npmjs.org/ --strict-ssl=true: exit 0; 12.22.1, MIT. @xmpp/client metadata query: exit 0; 0.14.0, ISC, stock SCRAM-SHA-1 module only. These queries used host npm; installation used pinned tools below.
- PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH npm install --ignore-scripts --no-audit --no-fund --cache /private/tmp/luma-xmpp-cache --fetch-retries=0 --fetch-timeout=15000 --prefix experiments/0002-xmpp-library: exit 0, 8 installed packages. No lifecycle scripts, TLS bypass or system changes. No clean-install/build/security audit claimed.
- npm view @xmpp/sasl-scram-sha-256 version and @xmpp/sasl-scram-sha-512 version with same registry/cache/timeout/strict-ssl flags: each exit 1, E404. Not evidence that no other implementation exists. npm view @xmpp/sasl-scram-sha-1@0.14.0 dependencies: exit 0, sasl-scram-sha-1 ^1.3.0.
- Source inspection: stanza/Client.js registers PLUS by priority without checking credentials; plugins/sasl.js success branch emits auth:success and requests restart without processSuccess/finalize. lib/sasl/index.js has verifier checking in finalize, but plugin never invokes it. Parser/StreamParser source has no configurable size/depth limits; not yet tested, not a second remediation. Browser platform advertises SHA-512 but default factory registers only SHA-256/SHA-1. No production readiness inference.
- Negative auth-path reproduction below: exit 0; assertions confirmed BOTH missing and forged server-final accepted before any server challenge/client proof, auth:success emitted and restart requested. Also confirmed factory chooses SCRAM-SHA-256-PLUS without checking TLS binding availability. This is an injected parsed-event unit reproduction using the actual installed Client and registered SASL handler, with outgoing send captured. It is NOT a WSS handshake, server interoperability or browser test.
- Initial exploratory glob rg command returned exit 1 because zsh could not expand stanza/sasl*; retried using rg --files and actual package paths. Web requests for stanzajs.org, guessed docs paths and mistaken xmpp.org RFC path failed; canonical RFC Editor and installed source supplied relevant facts.
Exact security reproduction
Run from project root with pinned Node:
PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH node --input-type=module <<'JS'
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
const require = createRequire(process.cwd() + '/experiments/0002-xmpp-library/package.json');
const Client = require('stanza/Client').default;
for (const value of [Buffer.alloc(0), Buffer.from('v=AAAAAAAAAAAAAAAAAAAAAAAAAAA=')]) {
const client = new Client({jid:'fixture@example.invalid', password:'fixture-only'});
const sent = [];
client.send = async (kind, stanza) => {sent.push({kind, stanza});};
let accepted = false;
let command;
client.on('auth:success', () => {accepted = true;});
await client.features.handlers.sasl({sasl:{mechanisms:['SCRAM-SHA-256']}}, c => {command=c;});
assert.equal(sent[0].stanza.mechanism, 'SCRAM-SHA-256');
client.emit('sasl', {type:'success', value});
assert.equal(accepted, true);
assert.equal(command, 'restart');
console.log('REPRODUCED: ' + (value.length ? 'forged' : 'missing') + ' server-final accepted before any challenge/proof');
}
const client = new Client({jid:'fixture@example.invalid', password:'fixture-only'});
assert.equal(client.sasl.createMechanism(['SCRAM-SHA-256','SCRAM-SHA-256-PLUS']).name, 'SCRAM-SHA-256-PLUS');
console.log('CONFIRMED: default factory selects PLUS without checking TLS binding availability');
JS
Fixture credentials are invented and never sent over a network. No crypto primitives written. Expected secure behavior would reject the success event; exit 0 here means the insecure behavior was reproduced, not that authentication passed acceptance.
Primary sources read 2026-10-15
- https://github.com/legastero/stanza — upstream TypeScript/JSON API, WSS configuration and MIT notice. Installed 12.22.1 source is the exact reproduction basis; homepage is not version-pinned evidence.
- https://registry.npmjs.org/stanza/12.22.1 — metadata resolved by npm and exact tarball/integrity locked locally; installed MIT LICENSE and browser/platform implementation inspected. Full transitive licensing review unfinished.
- https://github.com/xmppjs/xmpp.js and https://github.com/xmppjs/xmpp.js/blob/main/packages/client/index.js — alternative architecture.
- https://raw.githubusercontent.com/xmppjs/xmpp.js/main/packages/sasl/index.js — current upstream success path also returns done() without passing success payload to mechanism validation. Documentation/source comparison only, not an installed pinned xmpp.js reproduction.
- https://raw.githubusercontent.com/xmppjs/xmpp.js/main/packages/sasl-scram-sha-1/index.js — stock mechanism registration.
- https://www.rfc-editor.org/rfc/rfc7395.html — XMPP WebSocket subprotocol/framing/TLS.
- https://www.rfc-editor.org/rfc/rfc5802.html — SCRAM mutual authentication and server-final semantics.
Remaining acceptance and remediation
WSS handshake, valid SCRAM transcript, bounded parser behavior, extension roundtrip, browser build/execution and independent-server interoperability were NOT run. make check was not run for this incomplete evaluation. Source review is not a browser compatibility test. No certificate/CORS/channel-binding bypass, mock encryption or plaintext fallback was introduced.
Need one separately reviewed fail-closed SASL validation experiment before continuing original selection. It must use vetted library crypto (or a different maintained implementation), reject missing/forged/premature server-final, prove valid RFC fixtures and document integration through supported extension points. No upstream publication or private credentials required. Original retains WSS/parser/mechanism policy work after remediation; no need to expand into app/shared contracts.