Skip to content

test: guard shipped source against raw TLS clients - #41

Merged
code-yeongyu merged 6 commits into
mainfrom
test/tls-client-guard-20261010
Oct 11, 2026
Merged

code-yeongyu merged 6 commits into
mainfrom
test/tls-client-guard-20261010

Conversation

@code-yeongyu

@code-yeongyu code-yeongyu commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

AST repair after the H1/H2 review

Head: a5cba3b. This section supersedes the historical detector and gate details below.

  • Replaced the hand tokenizer with Acorn 8.15.0, a small dev-only dependency (this JavaScript repository had no parser dependency). Parser errors fail the guard and name the file. Unsupported TypeScript syntax likewise fails closed rather than being treated as inert JavaScript.
  • Detects all TLS/HTTPS/HTTP2 module acquisitions, default-as imports, export-from, static template specifiers, process.getBuiltinModule, binding/alias calls and every Bun.connect reference, including optional calls, destructuring declarations/assignments and call/apply. Exact normalized AST text and occurrence counts remain pinned; no file-level exemption.
  • Reviewer harness: 26/45 before -> 43/45 after; the only negatives are inbound Bun.listen and third-party ws. H1 desync cases: 0/4 -> 4/4. Midfile injections: 2578/3115 -> 3115/3115 caught. EOF injection misses: 0/45. H1/H2 plus malformed-source regressions were RED before implementation.
  • Final gates: Bun and Node guard+hygiene each 19 pass / 0 fail, syntax checks and git diff --check pass. Explicit Biome guard lint passes with zero warnings/errors. No repository typecheck/Biome scripts exist; no heavyweight tooling was added for those. Changed code files stay below 250 pure LOC.
  • Draft retained as requested. No PR merge or Slack. Evidence and adapted reviewer scripts held locally.

Summary

Add a tracked-shipped-source guard against unreviewed raw TLS clients for CVE-2026-48618, and collect it in both explicit CI runner lists.

Fixes #40

Related: code-yeongyu/senpi#3078, code-yeongyu/oh-my-openagent#9892. Detector precedents: senpi#3099 and oh-my-openagent#9893.

Changes

  • test/no-raw-tls-client.test.mjs scans git ls-files JavaScript/TypeScript, including src, CLI and extension source; tests, fixtures and declarations are excluded.
  • Its test-only detector catches direct clients, static/default/named/namespace/side-effect imports, require, dynamic/template-literal imports, export ... from, process.getBuiltinModule, and Bun.connect. Comment and literal-prose controls avoid false hits in the existing generated source. The positive matrix exercises 95 input forms.
  • The reviewed allowlist is empty because first-party shipped source has no direct TLS clients. The evaluator pins file + exact normalized call text + occurrence count + host-provenance reason, and self-tests reject different calls, wrong paths, extra/missing occurrences, stale entries and missing reasons. There is no file-wide bypass.
  • package.json adds the guard exactly once to test and test:node. The existing CI invokes both scripts.

Built dependency trace and verdict

The downstream bundle's tls.connect(options) belongs to ws@8.21.3.

OmO's packages/shared-skills/stage-omowright-runtime.mjs:39-47 builds OmOWright's src/index.js with Bun, --target=node --format=esm --minify-whitespace. A local rebuild with those settings and an external source map identifies node_modules/ws/lib/websocket.js. The installed runtime and rebuilt runtime have byte-identical require_websocket modules (22,560 bytes), and the mapped source matches the locked dependency's source.

Host/SNI provenance:

  1. src/connection.js:99-104 passes the user's CDP endpoint into CdpClient.
  2. src/core.js:93 selects the direct ws:/wss: endpoint or an HTTP discovery response's webSocketDebuggerUrl, and calls new WebSocket(Vn, { headers: jn }). No proxy, servername, agent, or custom createConnection option is passed.
  3. ws/lib/websocket.js:703-707 accepts a URL object or parses new URL(address).
  4. :752-758 selects tlsConnect and derives opts.host from parsedUrl.hostname.
  5. :1083-1090 sets options.servername to that host (or empty for an IP) before tls.connect(options).

Verdict: URL-derived and safe for this CVE. The built bundle is acceptable because the reachable host and SNI are normalized by the dependency before TLS. No runtime patch is needed. This conclusion is about the reviewed OmOWright call site, not arbitrary consumers supplying custom ws TLS options.

QA and RED -> GREEN

Local-only TLS measurement, Bun 1.4.2

Run the exported connect() path with client.reconnectDelaysMs: [0]. Intercept tls.connect before any external socket is opened; use a loopback-only HTTP server for the discovery case. Both installed and rebuilt runtimes produced the following results and exited 0:

Input path Recorded host Recorded servername
Direct WSS with U+3002 a.b.example.com a.b.example.com
Direct WSS with U+FF0E a.b.example.com a.b.example.com
Direct WSS with U+FF61 a.b.example.com a.b.example.com
Loopback discovery returning U+FF0E WSS a.b.example.com a.b.example.com

The same Bun 1.4.2 process confirms the vulnerability control against synthetic DNS:*.example.com: raw a\uFF0Eb.example.com is accepted, while new URL("https://a\uFF0Eb.example.com").hostname is rejected with ERR_TLS_CERT_ALTNAME_INVALID.

RED: temporarily add and stage src/tls-guard-negative-control.js containing:

export const unsafeClient = process.getBuiltinModule(`node:tls`);

bun test test/no-raw-tls-client.test.mjs exits 1: 3 pass, 1 fail, reporting:

src/tls-guard-negative-control.js:1  process.getBuiltinModule(`node:tls`)

GREEN: remove the owned negative control from file and index, then:

bun test test/no-raw-tls-client.test.mjs test/hygiene.test.mjs test/branding.test.mjs
17 pass, 0 fail; exit 0 (Bun 1.4.2)

node --test test/no-raw-tls-client.test.mjs
4 pass, 0 fail; exit 0 (local Node 26.7.0)

git diff --check
exit 0

Independent collection check confirms the new file occurs exactly once in each explicit runner list, and .github/workflows/ci.yml invokes both scripts. CI uses its existing Bun 1.4.3 / Node 24 configuration; this PR does not revert PR #39.

Evidence and the executable local-only probe are held locally under artifacts/omowright-tls-20261010/, outside the repository. Neither the probe, source maps nor the negative control is committed.

Probe SHA-256: 0485eeff76d26cab8783358b0106af44cc6b0a045d613112f95a1c50e0c6403e.

Limitations / delivery state

  • The configured LSP cannot initialize: TypeScript is absent and the configured Biome executable is not installed. Executed Bun/Node tests and whitespace checks are the available validation.
  • Full browser suites are delegated to the repository's existing CI rather than launching a browser locally for this static guard change.
  • Draft by request. Do not mark ready or merge as part of this task.

Summary by cubic

Adds a CI guard that fails when tracked shipped JS/TS source introduces an unreviewed direct tls/https/http2 client, closing regression risk for CVE-2026-48618 (fixes #40). The old scripts ran without this scan; no runtime behavior changes.

  • test/no-raw-tls-client.test.mjs runs the detector over git ls-files shipped source; tests, fixtures, and declarations are excluded.
  • test/tls-client-detector.mjs parses source with the Acorn AST (acorn@8.15.0 added as a dev dependency) to catch direct clients and all module acquisition forms, including global Bun access, destructuring assignment, and process.getBuiltinModule, ignoring comments and literal prose and counting call and member occurrences exactly.
  • The allowlist starts empty because shipped source has no direct TLS clients; entries must pin file, exact normalized call text, occurrence count, and reviewed host provenance, with no file-wide bypass.
  • The guard is wired into both test and test:node; the bundled tls.connect in ws@8.21.3 is URL-derived and safe here, so no runtime patch is needed.

Written for commit 8cf443f. Summary will update on new commits.

View guided diff Turn on auto-fix

@code-yeongyu
code-yeongyu marked this pull request as ready for review October 11, 2026 03:22
@code-yeongyu
code-yeongyu merged commit 1a7ba12 into main Oct 11, 2026
3 checks passed
@code-yeongyu
code-yeongyu deleted the test/tls-client-guard-20261010 branch October 11, 2026 03:23
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.

Guard shipped source against unreviewed raw TLS clients

1 participant