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: S00-003 cannot attest parser limits: Stanza 12.22.1 exposes no resource bounds and its persistent WebSocket parser accepts large/deep XML and reassembles incomplete documents across separate input messages.

Task: S00-003
Agent: auto-protocol-902594b44429
Role: protocol
Action: claim
Status: blocked

Task title: Проверить XMPP WSS/auth библиотеку
This commit is contained in:
wt committed 2026-10-15 02:24:00 +07:00
1 parent 1850dbc39f
commit f556fc0deb
14 files changed
+335 -24

No files matched your search

@@ -0,0 +1,57 @@
// Bounded diagnostic of the stock parser; passing means the defect reproduced.
// No network, credentials, vendor patch, or production implementation.
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
const require = createRequire(import.meta.url);
const Client = require('stanza/Client').default;
const {StreamParser} = require('stanza/jxt');
assert.equal(require('stanza/package.json').version, '12.22.1');
const tick = () => new Promise(resolve => setImmediate(resolve));
function harness() {
const client = new Client({autoReconnect: false});
// Same parser options as shipped transports/websocket.js.
const parser = new StreamParser({registry: client.stanzas,
wrappedStream: false, allowComments: false});
const received = [], errors = [];
parser.on('data', value => received.push(value));
parser.on('error', error => errors.push(error));
return {parser, received, errors};
}
const opening = '<message xmlns="jabber:client"><body>';
const closing = '</body></message>';
const split = harness();
split.parser.write(opening);
for (let i = 0; i < 16; i++) split.parser.write('a'.repeat(4096));
await tick();
assert.equal(split.errors.length, 0);
assert.equal(split.received.length, 0);
assert.equal(split.parser.destroyed, false);
split.parser.write(closing);
await tick();
assert.equal(split.errors.length, 0);
assert.equal(split.received.length, 1);
assert.equal(split.received[0].stanza.body.length, 65536);
split.parser.destroy();
console.log('stock: 18 separate writes reassembled into one 65536-byte body; no error');
const large = harness();
large.parser.write(opening + 'b'.repeat(1048576) + closing);
await tick();
assert.equal(large.errors.length, 0);
assert.equal(large.received.length, 1);
assert.equal(large.received[0].stanza.body.length, 1048576);
large.parser.destroy();
console.log('stock: 1048576-byte body accepted; no error');
const deep = harness();
deep.parser.write('<message xmlns="jabber:client">' + '<x>'.repeat(256) +
'</x>'.repeat(256) + '</message>');
await tick();
assert.equal(deep.errors.length, 0);
assert.equal(deep.received.length, 1);
let element = deep.received[0].xml, depth = 0;
while (element.children[0]) {element = element.children[0]; depth++;}
assert.equal(depth, 256);
deep.parser.destroy();
console.log('stock: 256 nested child elements accepted; no error');
+1 -1
View File
@@ -6,7 +6,7 @@
Зафиксировать Web scope, browser targets и проверенные кандидаты, не устанавливая непроверенный framework по догадке.
Задач: 17; entry: нет; exit: S00-010.
Задач: 18; entry: нет; exit: S00-010.
## [S01: Предметные контракты](stages/S01.md)
+3 -2
View File
@@ -1,12 +1,12 @@
# Матрица задач
Generated; state revision **41**. Canonical status: state/tasks.json.
Generated; state revision **43**. Canonical status: state/tasks.json.
| ID | Этап | Оператор | Reviewer | Статус | Owner | Зависимости | Задача |
| --- | --- | --- | --- | --- | --- | --- | --- |
| [S00-001](tasks/S00-001.md) | S00 | orchestrator | security | done | auto-orchestrator-48aab142ecde | | Утвердить Web-профиль |
| [S00-002](tasks/S00-002.md) | S00 | orchestrator | security | done | auto-orchestrator-68a05c587e33 | S00-001, S00-011, S00-012 | Выбрать framework и build runtime |
| [S00-003](tasks/S00-003.md) | S00 | protocol | qa | todo | | S00-001, S00-002, S00-017 | Проверить XMPP WSS/auth библиотеку |
| [S00-003](tasks/S00-003.md) | S00 | protocol | qa | blocked | auto-protocol-902594b44429 | S00-001, S00-002, S00-017, S00-018 | Проверить XMPP WSS/auth библиотеку |
| [S00-004](tasks/S00-004.md) | S00 | crypto | security | todo | | S00-001, S00-002 | Проверить browser OMEMO backend |
| [S00-005](tasks/S00-005.md) | S00 | storage | qa | todo | | S00-002 | Выбрать IndexedDB wrapper и migration policy |
| [S00-006](tasks/S00-006.md) | S00 | orchestrator | security | todo | | S00-002 | Зафиксировать browser/reference matrix |
@@ -20,6 +20,7 @@ Generated; state revision **41**. Canonical status: state/tasks.json.
| [S00-015](tasks/S00-015.md) | S00 | ci-cd | qa | done | auto-ci-cd-84e209103f24 | S00-001, S00-011, S00-013, S00-014, S00-016 | Устранить прерывание: Fix runner prompt delivery after partial stdin timeout |
| [S00-016](tasks/S00-016.md) | S00 | ci-cd | qa | done | auto-ci-cd-351a0cbbabef | S00-001, S00-011, S00-013, S00-014 | Restore reviewer model availability after provider capacity failure |
| [S00-017](tasks/S00-017.md) | S00 | protocol | security | done | auto-protocol-599343cd9e3f | S00-001, S00-002 | Establish fail-closed SCRAM server-final validation |
| [S00-018](tasks/S00-018.md) | S00 | protocol | security | todo | | S00-001, S00-002, S00-017 | Validate bounded standalone XML ingress for the XMPP candidate |
| [S00-010](tasks/S00-010.md) | S00 | qa | orchestrator | todo | | S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009 | Gate: Профиль и проверка стека |
| [S01-001](tasks/S01-001.md) | S01 | orchestrator | security | todo | | S00-010 | Описать identity/model contracts |
| [S01-002](tasks/S01-002.md) | S01 | orchestrator | security | todo | | S00-010, S01-001 | Описать async account context |
+3 -3
View File
@@ -14,7 +14,7 @@ Allocated означает наличие плана/приёмки, а не р
| ACC-001 | web | Web requirement; cross-platform clauses apply only in Web context. | S06-003, S21-001 |
| ACC-002 | web | Web requirement; cross-platform clauses apply only in Web context. | S06-001, S21-001 |
| ACC-003 | out_of_scope | Native host/port TCP configuration; Web uses ACC-004 WSS. | |
| ACC-004 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-003, S00-017, S05-001, S06-003, S21-001 |
| ACC-004 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-003, S00-017, S00-018, S05-001, S06-003, S21-001 |
| ACC-005 | web | Web requirement; cross-platform clauses apply only in Web context. | S05-001, S06-011, S21-001 |
| ACC-006 | web | Web requirement; cross-platform clauses apply only in Web context. | S06-003, S06-004, S21-001 |
| ACC-007 | web | Web requirement; cross-platform clauses apply only in Web context. | S06-002, S06-009, S20-008, S21-001 |
@@ -27,8 +27,8 @@ Allocated означает наличие плана/приёмки, а не р
| ACC-014 | web | Web requirement; cross-platform clauses apply only in Web context. | S01-002, S02-010, S06-006, S06-010, S21-001 |
| NET-001 | web | Web requirement; cross-platform clauses apply only in Web context. | S02-008, S05-001, S05-002, S05-009, S21-001 |
| NET-002 | out_of_scope | Native transport discovery; Web WSS addressed by ACC-004/NET-001. | |
| NET-003 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-003, S00-017, S05-003, S21-001 |
| NET-004 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-003, S00-017, S05-003, S05-009, S21-001 |
| NET-003 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-003, S00-017, S00-018, S05-003, S21-001 |
| NET-004 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-003, S00-017, S00-018, S05-003, S05-009, S21-001 |
| NET-005 | web | Web requirement; cross-platform clauses apply only in Web context. | S05-004, S21-001 |
| NET-006 | web | Web requirement; cross-platform clauses apply only in Web context. | S05-002, S05-010, S06-004, S20-002, S21-001 |
| NET-007 | web | Web requirement; cross-platform clauses apply only in Web context. | S05-007, S21-001 |
+2 -1
View File
@@ -8,7 +8,7 @@
- [S00-001](../tasks/S00-001.md): Утвердить Web-профиль — orchestrator; done.
- [S00-002](../tasks/S00-002.md): Выбрать framework и build runtime — orchestrator; done.
- [S00-003](../tasks/S00-003.md): Проверить XMPP WSS/auth библиотеку — protocol; todo.
- [S00-003](../tasks/S00-003.md): Проверить XMPP WSS/auth библиотеку — protocol; blocked.
- [S00-004](../tasks/S00-004.md): Проверить browser OMEMO backend — crypto; todo.
- [S00-005](../tasks/S00-005.md): Выбрать IndexedDB wrapper и migration policy — storage; todo.
- [S00-006](../tasks/S00-006.md): Зафиксировать browser/reference matrix — orchestrator; todo.
@@ -22,6 +22,7 @@
- [S00-015](../tasks/S00-015.md): Устранить прерывание: Fix runner prompt delivery after partial stdin timeout — ci-cd; done.
- [S00-016](../tasks/S00-016.md): Restore reviewer model availability after provider capacity failure — ci-cd; done.
- [S00-017](../tasks/S00-017.md): Establish fail-closed SCRAM server-final validation — protocol; done.
- [S00-018](../tasks/S00-018.md): Validate bounded standalone XML ingress for the XMPP candidate — protocol; todo.
- [S00-010](../tasks/S00-010.md): Gate: Профиль и проверка стека — qa; todo.
## Граница этапа
+2 -1
View File
@@ -1,7 +1,7 @@
id,stage,operator,reviewer,status,owner,depends_on,title
S00-001,S00,orchestrator,security,done,auto-orchestrator-48aab142ecde,,Утвердить Web-профиль
S00-002,S00,orchestrator,security,done,auto-orchestrator-68a05c587e33,"S00-001, S00-011, S00-012",Выбрать framework и build runtime
S00-003,S00,protocol,qa,todo,,"S00-001, S00-002, S00-017",Проверить XMPP WSS/auth библиотеку
S00-003,S00,protocol,qa,blocked,auto-protocol-902594b44429,"S00-001, S00-002, S00-017, S00-018",Проверить XMPP WSS/auth библиотеку
S00-004,S00,crypto,security,todo,,"S00-001, S00-002",Проверить browser OMEMO backend
S00-005,S00,storage,qa,todo,,S00-002,Выбрать IndexedDB wrapper и migration policy
S00-006,S00,orchestrator,security,todo,,S00-002,Зафиксировать browser/reference matrix
@@ -15,6 +15,7 @@ S00-014,S00,ci-cd,qa,done,auto-ci-cd-14343249da62,"S00-001, S00-011, S00-013",Fi
S00-015,S00,ci-cd,qa,done,auto-ci-cd-84e209103f24,"S00-001, S00-011, S00-013, S00-014, S00-016",Устранить прерывание: Fix runner prompt delivery after partial stdin timeout
S00-016,S00,ci-cd,qa,done,auto-ci-cd-351a0cbbabef,"S00-001, S00-011, S00-013, S00-014",Restore reviewer model availability after provider capacity failure
S00-017,S00,protocol,security,done,auto-protocol-599343cd9e3f,"S00-001, S00-002",Establish fail-closed SCRAM server-final validation
S00-018,S00,protocol,security,todo,,"S00-001, S00-002, S00-017",Validate bounded standalone XML ingress for the XMPP candidate
S00-010,S00,qa,orchestrator,todo,,"S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009",Gate: Профиль и проверка стека
S01-001,S01,orchestrator,security,todo,,S00-010,Описать identity/model contracts
S01-002,S01,orchestrator,security,todo,,"S00-010, S01-001",Описать async account context
1 id stage operator reviewer status owner depends_on title
2 S00-001 S00 orchestrator security done auto-orchestrator-48aab142ecde Утвердить Web-профиль
3 S00-002 S00 orchestrator security done auto-orchestrator-68a05c587e33 S00-001, S00-011, S00-012 Выбрать framework и build runtime
4 S00-003 S00 protocol qa todo blocked auto-protocol-902594b44429 S00-001, S00-002, S00-017 S00-001, S00-002, S00-017, S00-018 Проверить XMPP WSS/auth библиотеку
5 S00-004 S00 crypto security todo S00-001, S00-002 Проверить browser OMEMO backend
6 S00-005 S00 storage qa todo S00-002 Выбрать IndexedDB wrapper и migration policy
7 S00-006 S00 orchestrator security todo S00-002 Зафиксировать browser/reference matrix
15 S00-015 S00 ci-cd qa done auto-ci-cd-84e209103f24 S00-001, S00-011, S00-013, S00-014, S00-016 Устранить прерывание: Fix runner prompt delivery after partial stdin timeout
16 S00-016 S00 ci-cd qa done auto-ci-cd-351a0cbbabef S00-001, S00-011, S00-013, S00-014 Restore reviewer model availability after provider capacity failure
17 S00-017 S00 protocol security done auto-protocol-599343cd9e3f S00-001, S00-002 Establish fail-closed SCRAM server-final validation
18 S00-018 S00 protocol security todo S00-001, S00-002, S00-017 Validate bounded standalone XML ingress for the XMPP candidate
19 S00-010 S00 qa orchestrator todo S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009 Gate: Профиль и проверка стека
20 S01-001 S01 orchestrator security todo S00-010 Описать identity/model contracts
21 S01-002 S01 orchestrator security todo S00-010, S01-001 Описать async account context
+61 -1
View File
@@ -268,7 +268,8 @@
"depends_on": [
"S00-001",
"S00-002",
"S00-017"
"S00-017",
"S00-018"
],
"requirements": [
"ACC-004",
@@ -995,6 +996,65 @@
],
"context_budget_chars": 48000
},
{
"id": "S00-018",
"stage": "S00",
"kind": "blocker",
"root_task": "S00-003",
"blocker_depth": 1,
"unblocks": [
"S00-003"
],
"role": "protocol",
"reviewer_role": "security",
"title": "Validate bounded standalone XML ingress for the XMPP candidate",
"outcome": "One isolated runnable and independently reviewed ingress experiment enforces explicit finite XML resource limits and standalone text XML per WebSocket message before unsafe accumulation/import, through a supported library integration path.",
"depends_on": [
"S00-001",
"S00-002",
"S00-017"
],
"requirements": [
"ACC-004",
"NET-003",
"NET-004"
],
"scope": [
"experiments/0002-xmpp-library/parser-validation/**",
"docs/decisions/0002-xmpp-parser-validation.md"
],
"inputs": [
"docs/WEB_PROFILE.md",
"docs/ARCHITECTURE.md",
"docs/CONTRACTS.md",
"docs/TESTING.md",
"roles/protocol.md",
"docs/decisions/README.md",
"state/blockers/S00-018.md"
],
"spec_sections": [],
"ui_sections": [],
"steps": [
"Read original blocker evidence, bounded probe, shipped parser/transport APIs and RFC 7395 framing; reproduce the stock failure with finite synthetic input.",
"Choose and document a supported ingress integration using vetted existing XML parsing; keep limits experiment-local, do not implement a handwritten security XML parser or patch ignored vendor sources.",
"Enforce byte/depth/element/attribute budgets and complete single-document text-message framing before unbounded tree/import work; reject invalid input terminally and clear attempt state.",
"Add valid boundary and adversarial fixtures including incomplete messages, multiple roots, oversized tokens/attributes, deep XML, malformed XML and binary messages; verify rejection causes no stanza delivery or retained cross-message state.",
"Record exact dependencies/licenses/browser API constraints if adding packages, runnable commands/results and limitations, then submit for independent security review."
],
"acceptance": [
"Explicit finite byte/depth/element/attribute budgets are enforced before uncontrolled accumulation/import; boundary-valid stanza still parses with actual library behavior.",
"Each WebSocket message is one complete standalone text XML document; incomplete/multiple-root/binary input is rejected and cannot be revived by a later message.",
"Original large/deep/cross-message failure categories are rejected under documented local limits without post-import-only checks, vendor patch or TLS/CORS bypass.",
"One supported integration path and cleanup/reset behavior are demonstrated by runnable actual ingress tests; no production shared contract, auth policy or product limit change."
],
"checks": [
"Positive boundary-valid framed stanza using the actual candidate registry/parser and ingress integration.",
"Original bounded probe categories exceed local budgets or fail framing and produce terminal rejection without stanza emission.",
"Malformed/unfinished/multiple-root/binary/oversized-token/attribute/depth/element cases; no cross-message retained state or late revival.",
"Fresh attempt/reset accepts valid input; dependency pin/license/API and scope inspection."
],
"context_budget_chars": 48000
},
{
"id": "S00-010",
"stage": "S00",
+1 -1
View File
@@ -5,7 +5,7 @@
- Этап: S00
- Оператор: protocol
- Reviewer: qa
- Зависимости: S00-001, S00-002, S00-017
- Зависимости: S00-001, S00-002, S00-017, S00-018
- Требования: ACC-004, NET-003, NET-004
## Один результат
+62
View File
@@ -0,0 +1,62 @@
# S00-018: Validate bounded standalone XML ingress for the XMPP candidate
- Remediation для: S00-003; root: S00-003; depth: 1
> Generated from planning/tasks.json; status is in state/tasks.json.
- Этап: S00
- Оператор: protocol
- Reviewer: security
- Зависимости: S00-001, S00-002, S00-017
- Требования: ACC-004, NET-003, NET-004
## Один результат
One isolated runnable and independently reviewed ingress experiment enforces explicit finite XML resource limits and standalone text XML per WebSocket message before unsafe accumulation/import, through a supported library integration path.
## Разрешённые пути
- `experiments/0002-xmpp-library/parser-validation/**`
- `docs/decisions/0002-xmpp-parser-validation.md`
Не изменять другие modules, shared contracts или spec snapshots без изменения плана. Stem без расширения разрешает принятые stack-specific extensions и focused test рядом.
## Прочитать
- docs/WEB_PROFILE.md
- docs/ARCHITECTURE.md
- docs/CONTRACTS.md
- docs/TESTING.md
- roles/protocol.md
- docs/decisions/README.md
- state/blockers/S00-018.md
## Шаги
1. Read original blocker evidence, bounded probe, shipped parser/transport APIs and RFC 7395 framing; reproduce the stock failure with finite synthetic input.
2. Choose and document a supported ingress integration using vetted existing XML parsing; keep limits experiment-local, do not implement a handwritten security XML parser or patch ignored vendor sources.
3. Enforce byte/depth/element/attribute budgets and complete single-document text-message framing before unbounded tree/import work; reject invalid input terminally and clear attempt state.
4. Add valid boundary and adversarial fixtures including incomplete messages, multiple roots, oversized tokens/attributes, deep XML, malformed XML and binary messages; verify rejection causes no stanza delivery or retained cross-message state.
5. Record exact dependencies/licenses/browser API constraints if adding packages, runnable commands/results and limitations, then submit for independent security review.
## Приёмка
1. Explicit finite byte/depth/element/attribute budgets are enforced before uncontrolled accumulation/import; boundary-valid stanza still parses with actual library behavior.
2. Each WebSocket message is one complete standalone text XML document; incomplete/multiple-root/binary input is rejected and cannot be revived by a later message.
3. Original large/deep/cross-message failure categories are rejected under documented local limits without post-import-only checks, vendor patch or TLS/CORS bypass.
4. One supported integration path and cleanup/reset behavior are demonstrated by runnable actual ingress tests; no production shared contract, auth policy or product limit change.
## Focused checks
1. Positive boundary-valid framed stanza using the actual candidate registry/parser and ingress integration.
2. Original bounded probe categories exceed local budgets or fail framing and produce terminal rejection without stanza emission.
3. Malformed/unfinished/multiple-root/binary/oversized-token/attribute/depth/element cases; no cross-message retained state or late revival.
4. Fresh attempt/reset accepts valid input; dependency pin/license/API and scope inspection.
## Блокер и завершение запуска
Для всех ролей scope — только эта задача. При блокере создать issue JSON по state/ISSUE_TEMPLATE.json, вызвать escalate с текущим ID/role/agent, проверить status=blocked и resolution_task, затем немедленно завершить запуск. Не решать blocker и не выбирать следующую задачу самому. Новый агент назначается runner. Правки metadata через CLI — единственное исключение scope.
## Передача
Сохранить evidence/handoff; submit → review и завершить запуск. Reviewer также выполняет только эту задачу, включая обязательное escalate при блокере.
+22
View File
@@ -0,0 +1,22 @@
# Blocker S00-018
- Original task: S00-003
- Root task: S00-003
- Reporter: auto-protocol-902594b44429
- Role: protocol
- Original owner: auto-protocol-902594b44429
- Waits for user/external condition: False
## Cause
S00-003 cannot attest parser limits: Stanza 12.22.1 exposes no resource bounds and its persistent WebSocket parser accepts large/deep XML and reassembles incomplete documents across separate input messages.
## One remediation outcome
One isolated runnable and independently reviewed ingress experiment enforces explicit finite XML resource limits and standalone text XML per WebSocket message before unsafe accumulation/import, through a supported library integration path.
## Evidence / reproduction
Run the pinned Node command in state/evidence/S00-003-auto-protocol-902594b44429.md: parser-probe/reproduce.mjs exits 0 after observing acceptance of a 1 MiB body, depth 256, and unfinished XML retained across 18 writes. Inspect stanza/transports/websocket.js and jxt/StreamParser.d.ts for absent per-message completeness/resource-limit enforcement.
The reporting agent must stop now. A new agent implements only S00-018.
@@ -0,0 +1,39 @@
# S00-003 parser-limit blocker evidence
Executor: auto-protocol-902594b44429, protocol. Date: 2026-10-15.
Result: bounded diagnostic reproduced missing input limits; library selection remains incomplete.
Input: assigned master/startup/role/workflow documents, resume/show/packet, card and previous handoff; required docs/TESTING.md and docs/decisions/README.md; exact ACC-004/NET-003/NET-004; accepted ADR 0000, 0001-stack and 0002-xmpp-sasl-validation; all direct dependency executor/review evidence and handoffs. S00-017 is done and its prior SASL blocker is resolved within its reviewed fixture scope. S01 shared contracts are still future work; no shared interface is introduced.
Intended output: one library-selection ADR and runnable WSS/auth/parser/extension spike. Focused acceptance includes actual WSS handshake, verified SCRAM, bounded parser input and no invented TLS binding. This run stops before selection because parser bounds cannot be attested for the candidate's stock input path.
## Actual diagnostic
Added only experiments/0002-xmpp-library/parser-probe/reproduce.mjs, using the existing installed Stanza 12.22.1 and actual Client registry/StreamParser. No dependency, lockfile, accepted SASL plugin, vendor source, spec or app module changed. The script uses exactly the shipped WebSocket parser options: wrappedStream=false and allowComments=false. It asserts version, received stanza/body/XML depth and absence of error. No parser or registry result is stubbed. Finite fixtures have no accounts or real conversations; no network connection or authentication occurs.
Command:
`PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH node experiments/0002-xmpp-library/parser-probe/reproduce.mjs`
Exit 0, actual stdout:
```text
stock: 18 separate writes reassembled into one 65536-byte body; no error
stock: 1048576-byte body accepted; no error
stock: 256 nested child elements accepted; no error
```
Passing assertions mean stock limitations were reproduced, not safe parsing. The first case writes an unfinished message/body, sixteen 4096-byte chunks, then closing tags. Before closure there is no error/output and parser remains alive; after closure the entire body is emitted. The second and third cases show large and deep complete input accepted. This is not a memory-exhaustion benchmark or proof of infinite capacity; no crash/unbounded allocation was attempted and no product limit value is invented.
Version-pinned source inspection: stanza/jxt/StreamParser.d.ts exposes no byte/depth/element/attribute limit options. StreamParser.js builds nested element trees/text; Parser.js appends characters to recordBuffer across writes. stanza/transports/websocket.js creates one persistent parser, converts each socket.onmessage payload to text and writes it without checking completeness, size/depth, or text-message type. Therefore these separate parser writes model the transport's per-message ingress; actual WebSocket/TLS execution is NOT claimed. Browser WebSocket APIs also do not make a remote XML payload safe merely by using TLS.
Primary sources opened with web tool on 2026-10-15: RFC 7395 and upstream Stanza/xmpp.js repositories. [RFC 7395 section 3.3.3](https://www.rfc-editor.org/rfc/rfc7395.html#section-3.3.3) requires standalone XML per WebSocket message. The observed reassembly conflicts with that framing requirement when each write represents a distinct WebSocket message (inference from shipped transport source). Resource-limit absence is established by shipped API/source plus the finite examples, not by an RFC maximum. The alternative xmpp.js is not installed or tested and not selected as a safe replacement.
## Commands and limitations
- python3 scripts/tasks.py resume --agent auto-protocol-902594b44429; show S00-003; packet S00-003 --agent auto-protocol-902594b44429: exit 0 each; existing assigned task, no repeated claim.
- Initial git status --short: exit 0, only coordinator claim modification in state/tasks.json.
- Diagnostic command above: exit 0, all three cases reproduced in 0.154 seconds tool wall time.
- Exploratory guessed 0001-web-stack.md, lib/StreamParser.js and experiments/0017-scram-server-final paths were absent; actual required ADR/parser/remediation paths were located and read. These failed exploratory reads are not passed checks or missing required inputs.
Source edits stopped immediately after reproduction. No make check, clean npm ci, fresh SASL test run, browser build/runtime, real WSS handshake, complete NET-003 selection, extension roundtrip or independent interoperability was performed in this session. Parent npm test still points to absent future tests; do not use it as completed spike. No selection ADR was written. Existing dependency acceptance is reported as prior evidence, not re-executed validation. No certificate/CORS workaround, invented binding, crypto primitive, real credentials or Git mutation.
Next: separately reviewed atomic bounded frame/parser ingress experiment; original library selection resumes only in a fresh assigned session after resolver done and coordinator commit.
+8 -5
View File
@@ -1,11 +1,14 @@
# S00-003 blocked handoff
Executor: auto-protocol-826aa6bc12ef, protocol. Original scope: library selection and WSS/auth/parser/extension spike.
Executor: auto-protocol-902594b44429, protocol, 2026-10-15.
Original outcome remains library selection with WSS/auth/parser/extension spike.
Reached: inspected StanzaJS 12.22.1 and xmpp.js primary sources; created an exploratory pinned Stanza manifest/lock under experiments/0002-xmpp-library. Stanza's actual registered SASL handler was reproduced accepting empty and forged server-final before challenge/proof and requesting restart. See state/evidence/S00-003-auto-protocol-826aa6bc12ef.md for exact runnable reproduction/commands and limitations.
Prior S00-017 SASL validation remediation is independently accepted. Read its ADR/plugin/44-test evidence; this session did not rerun those tests or change that experiment. Stanza is still an unselected candidate and the parent exploratory manifest/lock remain incomplete.
Blocker: cannot attest safe SCRAM authentication with the candidate's unverified server-final success path. Its SCRAM implementation exposes finalize verification but its feature handler never calls it. Alternative xmpp.js upstream source likewise completes on success without verifier processing; this alternative was not installed/tested. A separately reviewed fail-closed SASL validation experiment is required; no handwritten cryptographic primitives or upstream source patch should be improvised in original selection.
New bounded probe: experiments/0002-xmpp-library/parser-probe/reproduce.mjs. With the accepted Node 24.21.0 runtime, its actual parser/Client registry accepts a 1 MiB body and 256 nested children and retains/reassembles unfinished XML across 18 writes into a 64 KiB body without error. StreamParserOptions exposes no resource-limit configuration. The shipped WebSocket transport forwards successive messages to that persistent parser without enforcing standalone XML or limits. Evidence and exact command: state/evidence/S00-003-auto-protocol-902594b44429.md. This is a local diagnostic, not WSS/server/browser execution or an exhaustion benchmark.
Source edits stopped. Manifest/lock are an unaccepted exploratory checkpoint, not a complete spike; npm test points at future tests. No ADR 0002 selection written. WSS, parser bounds, extension roundtrip, browser support and valid SCRAM are unverified. No make check result or release readiness claimed. Secrets/account fixtures are invented; no network auth was sent.
Blocker: cannot attest the required bounded parser ingress using the candidate's stock input path. Needs one separately reviewed experiment enforcing finite input resource limits and complete standalone text XML per WebSocket message, using vetted parsing and a supported integration path. Do not patch ignored vendor source or rely on post-import events after allocations. Keep policy local to the experiment; no shared contract/product-limit decision is authorized here.
Next input: new resolver agent implements only the atomic server-final validation outcome in the issue, with actual negative and valid-vector evidence; independent security reviewer validates it. After reviewed done, a fresh original executor resumes library selection and completes all original focused checks. Reporter must exit after escalate; coordinator owns commits/process launches.
Source edits stopped after diagnosis. No selection ADR, actual WSS handshake, browser build/runtime, complete mechanism policy, module extension roundtrip or independent interoperability is completed. No make check/clean install claimed for this run; source/accepted dependencies/specs were not altered beyond the bounded probe.
Next input: fresh resolver agent performs only the issue's parser ingress experiment and independent reviewer validates it. Only after reviewed done and coordinator commit may a new original executor resume remaining S00-003 acceptance. Current reporter must exit after escalation, cannot implement resolver, unblock, claim again or launch another agent.
@@ -0,0 +1,33 @@
{
"title": "Validate bounded standalone XML ingress for the XMPP candidate",
"reason": "S00-003 cannot attest parser limits: Stanza 12.22.1 exposes no resource bounds and its persistent WebSocket parser accepts large/deep XML and reassembles incomplete documents across separate input messages.",
"reproduction": "Run the pinned Node command in state/evidence/S00-003-auto-protocol-902594b44429.md: parser-probe/reproduce.mjs exits 0 after observing acceptance of a 1 MiB body, depth 256, and unfinished XML retained across 18 writes. Inspect stanza/transports/websocket.js and jxt/StreamParser.d.ts for absent per-message completeness/resource-limit enforcement.",
"role": "protocol",
"reviewer_role": "security",
"scope": [
"experiments/0002-xmpp-library/parser-validation/**",
"docs/decisions/0002-xmpp-parser-validation.md"
],
"outcome": "One isolated runnable and independently reviewed ingress experiment enforces explicit finite XML resource limits and standalone text XML per WebSocket message before unsafe accumulation/import, through a supported library integration path.",
"steps": [
"Read original blocker evidence, bounded probe, shipped parser/transport APIs and RFC 7395 framing; reproduce the stock failure with finite synthetic input.",
"Choose and document a supported ingress integration using vetted existing XML parsing; keep limits experiment-local, do not implement a handwritten security XML parser or patch ignored vendor sources.",
"Enforce byte/depth/element/attribute budgets and complete single-document text-message framing before unbounded tree/import work; reject invalid input terminally and clear attempt state.",
"Add valid boundary and adversarial fixtures including incomplete messages, multiple roots, oversized tokens/attributes, deep XML, malformed XML and binary messages; verify rejection causes no stanza delivery or retained cross-message state.",
"Record exact dependencies/licenses/browser API constraints if adding packages, runnable commands/results and limitations, then submit for independent security review."
],
"acceptance": [
"Explicit finite byte/depth/element/attribute budgets are enforced before uncontrolled accumulation/import; boundary-valid stanza still parses with actual library behavior.",
"Each WebSocket message is one complete standalone text XML document; incomplete/multiple-root/binary input is rejected and cannot be revived by a later message.",
"Original large/deep/cross-message failure categories are rejected under documented local limits without post-import-only checks, vendor patch or TLS/CORS bypass.",
"One supported integration path and cleanup/reset behavior are demonstrated by runnable actual ingress tests; no production shared contract, auth policy or product limit change."
],
"checks": [
"Positive boundary-valid framed stanza using the actual candidate registry/parser and ingress integration.",
"Original bounded probe categories exceed local budgets or fail framing and produce terminal rejection without stanza emission.",
"Malformed/unfinished/multiple-root/binary/oversized-token/attribute/depth/element cases; no cross-message retained state or late revival.",
"Fresh attempt/reset accepts valid input; dependency pin/license/API and scope inspection."
],
"depends_on": [],
"requires_user_input": false
}
+41 -9
View File
@@ -1,6 +1,6 @@
{
"schema_version": 1,
"revision": 41,
"revision": 43,
"tasks": {
"S00-001": {
"status": "done",
@@ -32,14 +32,16 @@
"completed_at": "2026-10-14T19:06:23+00:00"
},
"S00-003": {
"status": "todo",
"owner": null,
"started_at": "2026-10-14T19:06:24+00:00",
"reason": null,
"updated_at": "2026-10-14T19:20:57+00:00",
"blocked_by": [],
"status": "blocked",
"owner": "auto-protocol-902594b44429",
"started_at": "2026-10-14T19:20:57+00:00",
"reason": "S00-003 cannot attest parser limits: Stanza 12.22.1 exposes no resource bounds and its persistent WebSocket parser accepts large/deep XML and reassembles incomplete documents across separate input messages.",
"updated_at": "2026-10-14T19:24:00+00:00",
"blocked_by": [
"S00-018"
],
"resume_status": "in_progress",
"blocker_report": "state/blockers/S00-017.md",
"blocker_report": "state/blockers/S00-018.md",
"handoff": "state/handoffs/S00-003.md",
"previous_owner": "auto-protocol-826aa6bc12ef",
"resumed_after_blocker": true
@@ -1232,6 +1234,12 @@
"reviewer": "auto-security-9ab954f6e021",
"review_evidence": "state/evidence/S00-017-review.md",
"completed_at": "2026-10-14T19:20:57+00:00"
},
"S00-018": {
"status": "todo",
"owner": null,
"external_wait": false,
"reason": null
}
},
"events": [
@@ -1767,6 +1775,29 @@
"to": "done",
"reason": null,
"evidence": "state/evidence/S00-017-review.md"
},
{
"revision": 42,
"at": "2026-10-14T19:20:57+00:00",
"action": "claim",
"task": "S00-003",
"agent": "auto-protocol-902594b44429",
"role": "protocol",
"from": "todo",
"to": "in_progress",
"reason": null
},
{
"revision": 43,
"at": "2026-10-14T19:24:00+00:00",
"action": "escalate",
"task": "S00-003",
"resolution_task": "S00-018",
"agent": "auto-protocol-902594b44429",
"role": "protocol",
"from": "in_progress",
"to": "blocked",
"reason": "S00-003 cannot attest parser limits: Stanza 12.22.1 exposes no resource bounds and its persistent WebSocket parser accepts large/deep XML and reassembles incomplete documents across separate input messages."
}
],
"retired_agents": [
@@ -1776,6 +1807,7 @@
"auto-ci-cd-28868645424b",
"auto-qa-98b05bd56c25",
"auto-ci-cd-5475930af078",
"auto-protocol-826aa6bc12ef"
"auto-protocol-826aa6bc12ef",
"auto-protocol-902594b44429"
]
}