Skip to content

fix(javascript): omit fetch and WebSocket requests refused at construction - #10529

Open
Plastic-time wants to merge 3 commits into
morluto:mainfrom
Plastic-time:rrfz/omit-host-requests-refused-early
Open

Plastic-time wants to merge 3 commits into
morluto:mainfrom
Plastic-time:rrfz/omit-host-requests-refused-early

Conversation

@Plastic-time

@Plastic-time Plastic-time commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

JavaScript static analysis reported a request for fetch(...) and new WebSocket(...) calls that the host refuses while it builds the Request or the socket. Nothing is sent for these calls, and they no longer produce a requestOperations entry.

Fixes #10523

Problem and expected behavior

Measured in Node 24.22.1 (undici) against 127.0.0.1:9:

Call Result
fetch("http://user@host/x"), fetch("http://:pw@host/x") TypeError, URL includes credentials
fetch(url, { method: "G ET" }), "", "GET\n" TypeError, not a valid method
fetch(url, { method: "CONNECT" }), "trace", "Track" TypeError, forbidden method
fetch(url, { body: "x" }) with a string URL, { method: "get", body: "" }, { method: "head", body: 0 } TypeError, GET/HEAD cannot have a body
fetch(url, { headers: { "a b": "1" } }), "", "x-é" TypeError, invalid header name
new WebSocket("ws://host/x#a"), "ws://host/x#", "/s#a" SyntaxError, fragment
new WebSocket("ftp://host/x"), "file:///x", "mailto:x" SyntaxError, scheme
new WebSocket(url, "a b"), "", "a/b", ["chat", "chat"] SyntaxError, subprotocol

Accepted neighbors, which keep their request: { method: "PATCH" }, { method: "M-SEARCH" }, { method: "GET", body: null }, "http://:@host/x", new WebSocket("https://host/x"), "WSS://host/x", new WebSocket(url, null), new WebSocket(url, ["a", null]).

The Fetch standard's Request constructor and the WebSockets standard's constructor require these same refusals, so browsers behave the same way.

Change and scope

  • New javascriptHostRequestRefusals.ts holds the two checks. collectJavaScriptSemanticDataEffects filters the request candidates through it before response consumers are linked.
  • A relative URL without a fragment stays, because a browser resolves it against the document, as rejected_request_target already states.
  • A Request object as fetch input may carry its own method and body, so the default-GET body rule applies only to a string URL. Unknown members, spreads and computed header keys stay undecided. A spread argument stops the check for every later slot, because it can move a literal into a slot the host ignores.
  • Credentials count only when the scheme is followed by //. On a page with the same scheme, "http:user@host/x" is a relative path and names no user.
  • Not included: enum members such as mode, cache or redirect, and header values.

Contribution scope: ordinary fix within existing boundaries; maintainer scope decision not applicable.

Contract and boundary impact

  • Semantic owner and earliest changed stage: request candidates in javascriptSemanticDataEffects.ts.

  • Contribution scope fit and linked maintainer decision: not applicable.

  • CLI and MCP/tool-catalog contract: none.

  • Provider, bridge, target-format, or platform compatibility: none.

  • Evidence, artifact, provenance, or reconstruction contract: fewer false request facts; undecided calls are unchanged.

  • Target selection, authority, upstream behavior, and cleanup details: not applicable.

  • Generated metadata, package, or installation impact: none.

  • Read existing files or captured data.

Evidence and regression coverage

  • Tests added: src/domain/javascript/javascriptSemanticAnalysis.host_request_refusals.test.ts, one row per refused and accepted form.
  • Base reproduction: the new file on main source: 25 failed / 24 passed. With this change: 49 passed.

Validation performed

Windows 11 Home 10.0.26200 x64, Node 24.22.1, base 9e24b36.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: Node 24.22.1 (undici) measured; browsers were not run. The rules follow the Fetch and WebSockets standards.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: analysis only; the measurements targeted 127.0.0.1:9.

Author readiness

Human owner: @Plastic-time

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

…ction

The Request constructor rejects a URL with credentials, a method that is not
a token or is forbidden, a GET or HEAD body and a header name that is not a
token. The WebSocket constructor throws for a fragment, a scheme other than
ws, wss, http or https, and an invalid or repeated subprotocol. Neither sends
anything, so neither is a request.
A spread before the init or subprotocol argument can push the literal into a
slot the host ignores. A scheme without // is relative on a page with the
same scheme, so it proves no credentials.
@Plastic-time
Plastic-time marked this pull request as ready for review November 14, 2026 11:42
@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-14T11:42:42.285467Z
We couldn’t complete this review. Comment @codex review to try again.
3b5d1bc Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@greptile-apps

greptile-apps Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; both previous findings are fixed and no new blocking issues were found.

Summary

This PR omits requests that fetch or WebSocket refuses before sending anything.

  • JavaScript analysis omits fetch and WebSocket calls that fail before sending.

Reviews (2) · Last reviewed commit: "fix(javascript): read fetch header names..." · Reviewed by Greptile

…does

A header record with its own iterator, a computed key, a spread or a
__proto__ setter can supply other pairs, so its names stay undecided. The URL
parser trims surrounding C0 controls and spaces and drops tabs and newlines
before it finds credentials, so judge that string.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] JavaScript analysis reports fetch and WebSocket requests the host refuses to construct

1 participant