[GH-ISSUE #7434] [Bug] WebMCP discovery replaces malformed registration offsets with definite source coordinates #4439

Closed
opened 2026-10-31 00:49:48 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 27, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7434

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Process capture or runtime observation

Observed behavior

The public discover-webmcp-tools CLI succeeds when a selected CDP producer supplies lineNumber: -3 and columnNumber: 7.5, but returns registration_source.line: 0 and column: 7. It retains the registration without any webmcp_tools/invalid_protocol_value exclusion or unavailable section. The result presents a source position the producer never supplied. This mixed-offset case reproduced twice on current main; negative-only and fractional-only cases also reproduced once each.

Reproduction

Use Node.js 24.22.1 in a fresh checkout at the source commit below and prepare it with npm ci && npm run build:cached. The verification used prepared locked dependencies and reran the build; installation is a prerequisite, not a claimed verification step. Run this executed reduced replay from the repository root. It uses the repository's synthetic CDP server over loopback; no real browser, device or external service runs.

WORK="$(mktemp -d)"
mkdir -p "$WORK/home" "$WORK/config" "$WORK/data" "$WORK/cache" "$WORK/state" "$WORK/temp"
export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data"
export XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp"
node --import tsx --input-type=module <<'JS'
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import { startFakeCdpBrowser } from './tests/fixtures/fakeCdpBrowser.ts';
const run = promisify(execFile);
const browser = await startFakeCdpBrowser({
  webMcpTools: true,
  webMcpStackTrace: origin => ({callFrames: [{url: `${origin}/app.js`, lineNumber: -3, columnNumber: 7.5}]}),
});
try {
  const { stdout } = await run(process.execPath, [
    'scripts/rea.mjs', 'discover-webmcp-tools', browser.endpoint, 'allowed-page',
    '--allowed-origins', browser.allowedOrigin, '--observation-ms', '0', '--format', 'json',
  ]);
  const value = JSON.parse(stdout).normalized_result;
  console.log(JSON.stringify({total: value.tools.total, source: value.tools.items[0].registration_source, excluded: value.completeness.excluded, unavailable_sections: value.completeness.unavailable_sections}));
} finally { await browser.close(); }
JS

Expected behavior

Retain the tool while leaving the malformed registration source unknown and marking webmcp_tools incomplete with invalid_protocol_value. docs/browser-observation.md:28,486 documents this recovery and specifically gives registration_source: null for malformed stacks/top frames. The source-preservation invariant in AGENTS.md also requires explicit unknowns when normalization loses information. Valid zero and positive integer offsets must retain their observed values; an omitted stack must remain distinguishable from malformed evidence.

Impact and scope

P2: the returned evidence contains definite but fabricated coordinates, so consumers cannot distinguish a repaired offset from a genuine observation. The demonstrated scope is malformed finite CDP offsets in otherwise admitted WebMCP registrations. Real-browser frequency and downstream analyst consequences are unknown. No tested caller workaround recovers the discarded offsets. No execution, confidentiality, privilege or availability effect was established.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0. Source commit c79bd41b5d6d65b7b2a9b6e0b58d376fc36910d6, rebuilt with npm run build:cached.

Runtime and platform

Node.js v24.22.1; macOS, Darwin kernel 27.0.0; arm64. Locked dependencies; simulated CDP producer.

Target and artifact context

One synthetic admitted loopback page and its search_orders registration. The stack source is on the allowed origin; the registration frame, name, schema and annotations are valid. Only the source offsets vary in the numeric cases.

Interface

CLI

Earliest failure stage

Capture or observation

Relevant output or evidence

The reduced replay exited 0 and returned the following subset. The loopback port is assigned dynamically.

{"total":1,"source":{"url":"http://127.0.0.1:<port>/app.js","line":0,"column":7},"excluded":[{"section":"webmcp_tools","reason":"out_of_target_scope","count":2}],"unavailable_sections":[]}

An independent seven-case CLI probe retained exactly one registration in each case. Every call exited 0 with empty stderr:

Supplied stack or offsets Returned source line / column Invalid-value exclusion
-3 / 7.5 0 / 7 absent
-3 / -2 0 / 0 absent
7.5 / 3.2 7 / 3 absent
0 / 0 0 / 0 absent
12 / 4 12 / 4 absent
Omitted stack source is null absent
callFrames: [null] source is null present; count 1

The malformed-frame control also returns unavailable_sections: ["webmcp_tools"]; the other six do not. Evidence provenance: observed CLI output and controls; source-derived contract and cause. No restored implementation was tested.

Analysis or suspected cause

Source-derived: src/browser/CdpCaptureEventHelpers.ts:25-36 checks stack/frame container shape, so an object with invalid numeric coordinates passes. src/browser/CdpWebMcpDiscovery.ts:552-563,613-616 then uses its private numeric helper to clamp negatives and truncate fractions without reporting invalid coverage. The output schema at src/domain/webMcpDiscovery.ts:43-49 accepts the resulting nonnegative integers, allowing the public command to succeed.

Additional context

Open https://github.com/morluto/rea/issues/7370 covers analogous console and initiator offsets through a different numeric helper; fixing that helper alone leaves this WebMCP producer unchanged. Open https://github.com/morluto/rea/issues/7329 concerns comparison of already-unavailable WebMCP sources, whereas this failure occurs during discovery. Related merged https://github.com/morluto/rea/pull/6016 and closed https://github.com/morluto/rea/issues/5934 handle malformed stack/container shapes and console argument inventories; the malformed-frame control confirms that recovery still works, while numeric validation remains missing.

Proposed restoration check: repeat the malformed numeric inputs and require unknown source evidence plus invalid-value coverage, while preserving both integer controls and the omitted-stack behavior. MCP transport, real browsers, other platforms, the published package and regression onset were not tested.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The public CLI replaces malformed source evidence with definite different coordinates and omits the invalid-value marker; this is a bounded behavioral defect, while the valid integer controls pass and no severe wider consequence was established.
  • Workaround status: unverified
  • Workaround basis: No demonstrated caller procedure recovers or reliably identifies the discarded producer offsets from the returned discovery result.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7434 ## Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ## Area Process capture or runtime observation ## Observed behavior The public `discover-webmcp-tools` CLI succeeds when a selected CDP producer supplies `lineNumber: -3` and `columnNumber: 7.5`, but returns `registration_source.line: 0` and `column: 7`. It retains the registration without any `webmcp_tools/invalid_protocol_value` exclusion or unavailable section. The result presents a source position the producer never supplied. This mixed-offset case reproduced twice on current main; negative-only and fractional-only cases also reproduced once each. ## Reproduction Use Node.js 24.22.1 in a fresh checkout at the source commit below and prepare it with `npm ci && npm run build:cached`. The verification used prepared locked dependencies and reran the build; installation is a prerequisite, not a claimed verification step. Run this executed reduced replay from the repository root. It uses the repository's synthetic CDP server over loopback; no real browser, device or external service runs. ```sh WORK="$(mktemp -d)" mkdir -p "$WORK/home" "$WORK/config" "$WORK/data" "$WORK/cache" "$WORK/state" "$WORK/temp" export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" export XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp" node --import tsx --input-type=module <<'JS' import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; import { startFakeCdpBrowser } from './tests/fixtures/fakeCdpBrowser.ts'; const run = promisify(execFile); const browser = await startFakeCdpBrowser({ webMcpTools: true, webMcpStackTrace: origin => ({callFrames: [{url: `${origin}/app.js`, lineNumber: -3, columnNumber: 7.5}]}), }); try { const { stdout } = await run(process.execPath, [ 'scripts/rea.mjs', 'discover-webmcp-tools', browser.endpoint, 'allowed-page', '--allowed-origins', browser.allowedOrigin, '--observation-ms', '0', '--format', 'json', ]); const value = JSON.parse(stdout).normalized_result; console.log(JSON.stringify({total: value.tools.total, source: value.tools.items[0].registration_source, excluded: value.completeness.excluded, unavailable_sections: value.completeness.unavailable_sections})); } finally { await browser.close(); } JS ``` ## Expected behavior Retain the tool while leaving the malformed registration source unknown and marking `webmcp_tools` incomplete with `invalid_protocol_value`. `docs/browser-observation.md:28,486` documents this recovery and specifically gives `registration_source: null` for malformed stacks/top frames. The source-preservation invariant in `AGENTS.md` also requires explicit unknowns when normalization loses information. Valid zero and positive integer offsets must retain their observed values; an omitted stack must remain distinguishable from malformed evidence. ## Impact and scope P2: the returned evidence contains definite but fabricated coordinates, so consumers cannot distinguish a repaired offset from a genuine observation. The demonstrated scope is malformed finite CDP offsets in otherwise admitted WebMCP registrations. Real-browser frequency and downstream analyst consequences are unknown. No tested caller workaround recovers the discarded offsets. No execution, confidentiality, privilege or availability effect was established. ## REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Source commit `c79bd41b5d6d65b7b2a9b6e0b58d376fc36910d6`, rebuilt with `npm run build:cached`. ## Runtime and platform Node.js v24.22.1; macOS, Darwin kernel 27.0.0; arm64. Locked dependencies; simulated CDP producer. ## Target and artifact context One synthetic admitted loopback page and its `search_orders` registration. The stack source is on the allowed origin; the registration frame, name, schema and annotations are valid. Only the source offsets vary in the numeric cases. ## Interface CLI ## Earliest failure stage Capture or observation ## Relevant output or evidence The reduced replay exited 0 and returned the following subset. The loopback port is assigned dynamically. ```json {"total":1,"source":{"url":"http://127.0.0.1:<port>/app.js","line":0,"column":7},"excluded":[{"section":"webmcp_tools","reason":"out_of_target_scope","count":2}],"unavailable_sections":[]} ``` An independent seven-case CLI probe retained exactly one registration in each case. Every call exited 0 with empty stderr: | Supplied stack or offsets | Returned source line / column | Invalid-value exclusion | | --- | --- | --- | | -3 / 7.5 | 0 / 7 | absent | | -3 / -2 | 0 / 0 | absent | | 7.5 / 3.2 | 7 / 3 | absent | | 0 / 0 | 0 / 0 | absent | | 12 / 4 | 12 / 4 | absent | | Omitted stack | source is null | absent | | `callFrames: [null]` | source is null | present; count 1 | The malformed-frame control also returns `unavailable_sections: ["webmcp_tools"]`; the other six do not. Evidence provenance: observed CLI output and controls; source-derived contract and cause. No restored implementation was tested. ## Analysis or suspected cause Source-derived: `src/browser/CdpCaptureEventHelpers.ts:25-36` checks stack/frame container shape, so an object with invalid numeric coordinates passes. `src/browser/CdpWebMcpDiscovery.ts:552-563,613-616` then uses its private numeric helper to clamp negatives and truncate fractions without reporting invalid coverage. The output schema at `src/domain/webMcpDiscovery.ts:43-49` accepts the resulting nonnegative integers, allowing the public command to succeed. ## Additional context Open https://github.com/morluto/rea/issues/7370 covers analogous console and initiator offsets through a different numeric helper; fixing that helper alone leaves this WebMCP producer unchanged. Open https://github.com/morluto/rea/issues/7329 concerns comparison of already-unavailable WebMCP sources, whereas this failure occurs during discovery. Related merged https://github.com/morluto/rea/pull/6016 and closed https://github.com/morluto/rea/issues/5934 handle malformed stack/container shapes and console argument inventories; the malformed-frame control confirms that recovery still works, while numeric validation remains missing. Proposed restoration check: repeat the malformed numeric inputs and require unknown source evidence plus invalid-value coverage, while preserving both integer controls and the omitted-stack behavior. MCP transport, real browsers, other platforms, the published package and regression onset were not tested. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The public CLI replaces malformed source evidence with definite different coordinates and omits the invalid-value marker; this is a bounded behavioral defect, while the valid integer controls pass and no severe wider consequence was established. - Workaround status: unverified - Workaround basis: No demonstrated caller procedure recovers or reliably identifies the discarded producer offsets from the returned discovery result.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4439
No description provided.