Files
LumaWeb/state/evidence/S00-003-auto-protocol-826aa6bc12ef.md
T
wt c73d9cef45 S00-003: Record blocked task and remediation handoff
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 библиотеку
2026-10-15 02:09:23 +07:00

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

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.