Skip to content

fix(main): let Stop and timeouts end a pending DNS lookup - #254

Merged
johnny4young merged 2 commits into
mainfrom
fix/network-dns-cancel-and-header-keys
Oct 15, 2026
Merged

johnny4young merged 2 commits into
mainfrom
fix/network-dns-cancel-and-header-keys

Conversation

@johnny4young

Copy link
Copy Markdown
Owner

Summary

Two follow-ups from the October review of the desktop network guard (src/main/networkTargetPolicy.ts):

  1. Hanging DNS ignored Stop and the deadline. resolveGuardedNetworkTarget awaited dns.lookup with no abort signal. HTTP/SSE only armed its abort on the later fetch, and WebSocket only after the lookup, so a resolver that never answered kept the request alive past Stop and past its timeout.
    • The policy now takes an optional signal and races the lookup against it. An aborted lookup rethrows the caller's abort, never an SsrfBlockedError, so transports keep classifying it as cancel or timeout.
    • httpProxy.ts passes its request controller.
    • httpWebSocket.ts bounds the lookup with the same Stop and timeoutMs it already uses for the connection; the result is "Request cancelled" or timeout, matching its existing messages.
  2. __proto__ WebSocket header. toHeaderRecord built a plain object, so assigning a header named __proto__ changed the prototype instead of adding a header, and it was silently dropped. The record is now null-prototype (the same class of bug fixed in urlParse).

The DNS phase gets its own timeoutMs budget before the connection's; previously it had none.

Validation

  • New tests: HTTP timeout with a never-answering lookup (fetch never called); WebSocket Stop and deadline during DNS; a __proto__ header received on the wire by a real ws server (checked via rawHeaders). All three fail without the fix; two of them hang until the test timeout.
  • tests/main + tests/ipc: 1060 passed; tsc --noEmit, lint, changelog:check green.
  • pnpm run smoke:desktop:stagewright: launch + snapshot, 0 console errors. It does not exercise a hanging resolver; the transport tests cover that path.

- The desktop HTTP/SSE and WebSocket transports awaited the destination lookup without their abort signal, so a resolver that never answered delayed Stop and the request deadline indefinitely.
- resolveGuardedNetworkTarget accepts the caller's signal and settles with the caller's cancel or timeout, never a policy rejection. HTTP passes its request controller; WebSocket bounds the lookup with the same Stop and deadline it already applies to the connection.
- Build WebSocket handshake headers on a null-prototype object so a header named __proto__ is sent instead of silently dropped.

Changelog: none
- HttpRequestHeader has no id field; typecheck:tests rejected the literal.

Changelog: none
@johnny4young
johnny4young merged commit 6ef5480 into main Oct 15, 2026
13 checks passed
@johnny4young
johnny4young deleted the fix/network-dns-cancel-and-header-keys branch October 15, 2026 04:13
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.

1 participant