[GH-ISSUE #5178] [Bug] Explicit default-port Inspector and CDP endpoints fail request validation #3179

Closed
opened 2026-10-31 00:37:33 +00:00 by bsakaguchi · 2 comments
Owner

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

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

Runtime target listing, runtime observation, and browser target listing reject explicitly written :80 loopback endpoints with invalid_request. This was reproduced through the public CLI on the source-built main baseline below. Browser listing rejects both HTTP discovery and browser WebSocket forms. Rejection happens before discovery, even though the error requires an explicit port and the input includes one.

Reproduction

In a built source checkout of the main baseline below with its pinned Node runtime and locked dependencies, run:

node scripts/rea.mjs list-javascript-runtime-targets 'http://127.0.0.1:80' --json
node scripts/rea.mjs observe-javascript-runtime 'http://127.0.0.1:80' fixture --json
node scripts/rea.mjs list-browser-targets 'http://127.0.0.1:80' --json
node scripts/rea.mjs list-browser-targets 'ws://127.0.0.1:80/devtools/browser/fixture' --json

Each command was run once and exited 1 with an endpoint validation error. No running target is needed to reproduce this early failure; fixture is a synthetic identifier. No actual Inspector attach or real-browser connection is claimed.

The following source-schema control also ran:

node --import tsx --input-type=module <<'JS'
import { browserEndpointSchema, browserObservationEndpointSchema } from './src/domain/browserObservation.ts';
for (const host of ['127.0.0.1', '[::1]']) {
  for (const port of [80, 81]) {
    const http = `http://${host}:${port}`;
    const ws = `ws://${host}:${port}/devtools/browser/fixture`;
    console.log(http, browserEndpointSchema.safeParse(http).success);
    console.log(ws, browserObservationEndpointSchema.safeParse(ws).success);
  }
}
console.log('implicit', browserEndpointSchema.safeParse('http://127.0.0.1').success);
JS

Both literal loopback families returned false for the default port and true for the nondefault port using the appropriate HTTP/browser WebSocket schema. The implicit-port control returned false.

Expected behavior

The browser request boundary documents HTTP and browser WebSocket endpoints with an explicit PORT and rejects implicit ports; it does not exclude explicit default ports. Runtime list/observe requests share the HTTP endpoint schema. Explicit default-port inputs should pass endpoint validation and advance to discovery or connection. Subsequent listener availability and target selection remain separate checks.

Impact and scope

The observed impact is bounded input incompatibility: runtime and browser workflows configured on the default port cannot get past endpoint validation. IPv4 was tested through the public CLI; IPv4 and IPv6 were tested through schemas. An owned nondefault-port HTTP Inspector fixture completed runtime listing successfully. Real deployment frequency and default-port provider connectivity were not measured. HTTPS and secure WebSockets are independently unsupported and are outside this finding.

REA version

Executed source-built main: 9af0b6113c, reporting CLI version 6.7.0. Latest published release: rea-agents 6.7.0, tag rea-agents-6.7.0 at 27dc42d102. Relevant release schemas, runtime and browser CLI handlers, tool bindings and cited docs are byte-identical to main. Release behavior is source-derived; the published package runtime was not executed separately.

Runtime and platform

Node 24.18.0; macOS arm64.

Target and artifact context

Synthetic loopback endpoint strings. A separate owned HTTP Inspector fixture on an ephemeral nondefault port returned a version object and an empty target list. No real application, browser profile or private target data was used.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

For runtime listing, the observed error included:

{
  "code": "invalid_request",
  "category": "invalid_input",
  "details": {
    "operation": "list_javascript_runtime_targets",
    "issues": [{
      "path": ["inspector_endpoint"],
      "reason": "invalid_value",
      "message": "CDP endpoint must be an explicit-port HTTP URL on 127.0.0.1 or ::1"
    }]
  }
}

The other HTTP cases identified their endpoint field with the same constraint. The browser WebSocket case identified cdp_endpoint with CDP browser WebSocket must be ws://127.0.0.1:PORT/devtools/browser/ID or ws://[::1]:PORT/devtools/browser/ID. All four had empty stderr.

Source-derived cause: src/domain/browserObservation.ts:56-80 requires a nonempty normalized URL port. Local URL parsing returned an empty normalized port for explicitly written :80. Runtime schema bindings are in src/domain/javascript/javascriptRuntimeObservation.ts:8-15 and :31-37. CLI validation returns before provider discovery at src/cliJavaScriptRuntimeCommands.ts:55-68 and src/cli/browserCommands.ts:60-68.

The nondefault-port fixture returned exit 0 and an empty inventory, receiving exactly /json/version and /json/list. Its version reply was {"Browser":"Node/fixture","Protocol-Version":"1.3","V8-Version":"fixture"} and its list reply was []; this was mocked-provider testing. Attempting to bind that fixture on port 80 failed with EACCES, so a live default-port connection was not exercised. The validation failure above does not depend on that listener.

Typed outcome or recovery expected

Accept explicitly spelled default ports at endpoint validation. With an owned listener, proceed to discovery; without one, report a connection failure rather than a missing-explicit-port error. Keep implicit ports, nonloopback hosts and other unsupported endpoint shapes rejected. Retain nondefault-port behavior and validate both literal loopback families and both supported browser transports.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A documented explicit endpoint spelling is rejected before discovery, blocking workflows configured on that port. The observed defect is bounded to these request inputs; real-provider frequency and default-port connectivity were not measured.
  • Workaround status: unverified
  • Workaround basis: A nondefault-port owned fixture succeeds, but permission and ability to rebind or proxy a caller's fixed target were not established. No workaround preserving a fixed default-port endpoint was verified.
Originally created by @coygeek on GitHub (Oct 19, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5178 ## 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 Runtime target listing, runtime observation, and browser target listing reject explicitly written `:80` loopback endpoints with `invalid_request`. This was reproduced through the public CLI on the source-built main baseline below. Browser listing rejects both HTTP discovery and browser WebSocket forms. Rejection happens before discovery, even though the error requires an explicit port and the input includes one. ## Reproduction In a built source checkout of the main baseline below with its pinned Node runtime and locked dependencies, run: ```sh node scripts/rea.mjs list-javascript-runtime-targets 'http://127.0.0.1:80' --json node scripts/rea.mjs observe-javascript-runtime 'http://127.0.0.1:80' fixture --json node scripts/rea.mjs list-browser-targets 'http://127.0.0.1:80' --json node scripts/rea.mjs list-browser-targets 'ws://127.0.0.1:80/devtools/browser/fixture' --json ``` Each command was run once and exited 1 with an endpoint validation error. No running target is needed to reproduce this early failure; `fixture` is a synthetic identifier. No actual Inspector attach or real-browser connection is claimed. The following source-schema control also ran: ```sh node --import tsx --input-type=module <<'JS' import { browserEndpointSchema, browserObservationEndpointSchema } from './src/domain/browserObservation.ts'; for (const host of ['127.0.0.1', '[::1]']) { for (const port of [80, 81]) { const http = `http://${host}:${port}`; const ws = `ws://${host}:${port}/devtools/browser/fixture`; console.log(http, browserEndpointSchema.safeParse(http).success); console.log(ws, browserObservationEndpointSchema.safeParse(ws).success); } } console.log('implicit', browserEndpointSchema.safeParse('http://127.0.0.1').success); JS ``` Both literal loopback families returned `false` for the default port and `true` for the nondefault port using the appropriate HTTP/browser WebSocket schema. The implicit-port control returned `false`. ## Expected behavior The [browser request boundary](https://github.com/morluto/rea/blob/9af0b6113c81803f88ec7d242e8fabaaa5d7f1f3/docs/browser-observation.md#L181-L190) documents HTTP and browser WebSocket endpoints with an explicit PORT and rejects implicit ports; it does not exclude explicit default ports. Runtime list/observe requests share the HTTP endpoint schema. Explicit default-port inputs should pass endpoint validation and advance to discovery or connection. Subsequent listener availability and target selection remain separate checks. ## Impact and scope The observed impact is bounded input incompatibility: runtime and browser workflows configured on the default port cannot get past endpoint validation. IPv4 was tested through the public CLI; IPv4 and IPv6 were tested through schemas. An owned nondefault-port HTTP Inspector fixture completed runtime listing successfully. Real deployment frequency and default-port provider connectivity were not measured. HTTPS and secure WebSockets are independently unsupported and are outside this finding. ## REA version Executed source-built main: 9af0b6113c81803f88ec7d242e8fabaaa5d7f1f3, reporting CLI version 6.7.0. Latest published release: rea-agents 6.7.0, tag rea-agents-6.7.0 at 27dc42d10249f0410904a75c0997842eb03b931c. Relevant release schemas, runtime and browser CLI handlers, tool bindings and cited docs are byte-identical to main. Release behavior is source-derived; the published package runtime was not executed separately. ## Runtime and platform Node 24.18.0; macOS arm64. ## Target and artifact context Synthetic loopback endpoint strings. A separate owned HTTP Inspector fixture on an ephemeral nondefault port returned a version object and an empty target list. No real application, browser profile or private target data was used. ## Interface CLI ## Earliest failure stage Request parsing or validation ## Relevant output or evidence For runtime listing, the observed error included: ```json { "code": "invalid_request", "category": "invalid_input", "details": { "operation": "list_javascript_runtime_targets", "issues": [{ "path": ["inspector_endpoint"], "reason": "invalid_value", "message": "CDP endpoint must be an explicit-port HTTP URL on 127.0.0.1 or ::1" }] } } ``` The other HTTP cases identified their endpoint field with the same constraint. The browser WebSocket case identified `cdp_endpoint` with `CDP browser WebSocket must be ws://127.0.0.1:PORT/devtools/browser/ID or ws://[::1]:PORT/devtools/browser/ID`. All four had empty stderr. Source-derived cause: `src/domain/browserObservation.ts:56-80` requires a nonempty normalized URL port. Local URL parsing returned an empty normalized port for explicitly written `:80`. Runtime schema bindings are in `src/domain/javascript/javascriptRuntimeObservation.ts:8-15` and `:31-37`. CLI validation returns before provider discovery at `src/cliJavaScriptRuntimeCommands.ts:55-68` and `src/cli/browserCommands.ts:60-68`. The nondefault-port fixture returned exit 0 and an empty inventory, receiving exactly `/json/version` and `/json/list`. Its version reply was `{"Browser":"Node/fixture","Protocol-Version":"1.3","V8-Version":"fixture"}` and its list reply was `[]`; this was mocked-provider testing. Attempting to bind that fixture on port 80 failed with `EACCES`, so a live default-port connection was not exercised. The validation failure above does not depend on that listener. ## Typed outcome or recovery expected Accept explicitly spelled default ports at endpoint validation. With an owned listener, proceed to discovery; without one, report a connection failure rather than a missing-explicit-port error. Keep implicit ports, nonloopback hosts and other unsupported endpoint shapes rejected. Retain nondefault-port behavior and validate both literal loopback families and both supported browser transports. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A documented explicit endpoint spelling is rejected before discovery, blocking workflows configured on that port. The observed defect is bounded to these request inputs; real-provider frequency and default-port connectivity were not measured. - Workaround status: unverified - Workaround basis: A nondefault-port owned fixture succeeds, but permission and ability to rebind or proxy a caller's fixed target were not established. No workaround preserving a fixed default-port endpoint was verified.
Author
Owner

@XinwangTao commented on GitHub (Oct 19, 2026):

Good catch — this is a classic URL normalization pitfall. new URL('http://127.0.0.1:80').port returns '' because the URL standard treats :80 as the implicit default for http, so any nonempty check on the normalized port will always reject explicitly spelled default ports. Since the docs explicitly allow default-port spellings, the schema should derive an effective port (url.port || (url.protocol === 'http:' ? '80' : '443')) before the nonempty check instead of relying on the normalized value — that keeps implicit-port inputs rejected as intended while accepting explicit :80/:443. The source-schema control is a nice minimal repro; agree with the P2 assessment.

<!-- gh-comment-id:6259866514 --> @XinwangTao commented on GitHub (Oct 19, 2026): Good catch — this is a classic URL normalization pitfall. `new URL('http://127.0.0.1:80').port` returns `''` because the URL standard treats :80 as the implicit default for http, so any nonempty check on the normalized port will always reject explicitly spelled default ports. Since the docs explicitly allow default-port spellings, the schema should derive an effective port (`url.port || (url.protocol === 'http:' ? '80' : '443')`) before the nonempty check instead of relying on the normalized value — that keeps implicit-port inputs rejected as intended while accepting explicit `:80`/`:443`. The source-schema control is a nice minimal repro; agree with the P2 assessment.
Author
Owner

@coygeek commented on GitHub (Oct 24, 2026):

Checked the reported fix on main at d87e73f2db.

The endpoint owner now extracts an explicitly spelled port from the original authority before URL normalization erases a default. Both HTTP and browser WebSocket schemas retain that explicit authority. The regression tests :80 on IPv4 and IPv6, idempotent HTTP normalization, recorded endpoints and WebSocket redaction, and rejects implicit/nonloopback forms.

Implementation: browserObservation.ts, browserObservation.ts.

The relevant regression checks in browserObservation.test.ts passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.

<!-- gh-comment-id:6380781636 --> @coygeek commented on GitHub (Oct 24, 2026): Checked the reported fix on `main` at d87e73f2db50be72d33a4b3c7199af35518b441c. The endpoint owner now extracts an explicitly spelled port from the original authority before URL normalization erases a default. Both HTTP and browser WebSocket schemas retain that explicit authority. The regression tests :80 on IPv4 and IPv6, idempotent HTTP normalization, recorded endpoints and WebSocket redaction, and rejects implicit/nonloopback forms. Implementation: [browserObservation.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/browserObservation.ts#L69), [browserObservation.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/browserObservation.ts#L82). The relevant regression checks in [browserObservation.test.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/browserObservation.test.ts) passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.
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#3179
No description provided.