Skip to content

[Fix] Production-grade SSRF guard with numeric IP parsing and DNS pre-resolution#189

Merged
samzong merged 1 commit intomainfrom
fix/ssrf-private-host-check
Mar 27, 2026
Merged

[Fix] Production-grade SSRF guard with numeric IP parsing and DNS pre-resolution#189
samzong merged 1 commit intomainfrom
fix/ssrf-private-host-check

Conversation

@samzong
Copy link
Copy Markdown
Collaborator

@samzong samzong commented Mar 27, 2026

Summary

Replace the string-prefix SSRF check in auto-extract.ts with a proper numeric IP parsing module and DNS pre-resolution guard, extracted into a shared net/ layer used by all outbound fetch paths.

Type of change

  • [Fix] bug fix

Why is this needed?

The previous isPrivateHost only matched three literal strings (localhost, 127.0.0.1, ::1). This missed all RFC 1918 ranges, link-local, CGNAT, reserved, and IPv6 private addresses. The todo.md suggested a string-prefix approach which introduced false positives (blocking 10.cdn.example.com) and still missed IPv6-mapped IPv4 and DNS rebinding vectors. Additionally, artifact-handlers.ts had a bare net.fetch with zero SSRF protection.

What changed?

  • New src/main/net/ssrf-guard.ts: Numeric IPv4/IPv6 range checks via node:net isIP() covering 10/8, 172.16/12, 192.168/16, 127/8, 169.254/16, 0/8, 100.64/10 (CGNAT), 198.18/15 (benchmark), 240/4 (reserved), IPv6 loopback/ULA/link-local, and IPv4-mapped IPv6 (both dotted and hex forms). DNS pre-resolution via node:dns/promises blocks rebinding attacks.
  • New src/main/net/safe-fetch.ts: Unified HTTPS-only fetch wrapper with SSRF guard, configurable size limit (default 10MB), and timeout (default 10s).
  • auto-extract.ts: Removed inline isPrivateHost, fetchToBuffer, and related constants. Now uses safeFetch.
  • artifact-handlers.ts: Replaced unprotected net.fetch in artifact:save-image-url with safeFetch.

Architecture impact

  • Owning layer: main
  • Cross-layer impact: none
  • Invariants touched from docs/architecture-invariants.md: none
  • Why those invariants remain protected: changes are confined to main-process network utilities; no renderer, preload, or shared contract changes

Linked issues

Closes the SSRF private host check gap identified in the worktree todo.

Validation

  • pnpm lint
  • pnpm test
  • pnpm check:ui-contract
  • pnpm check (full gate: lint + architecture + ui-contract + renderer-copy + i18n + dead-code + format + typecheck + test)
  • pnpm build
  • Manual smoke test

Commands, screenshots, or notes:

pnpm check -> all green
148 tests passed (49 ssrf-guard + 7 safe-fetch + 92 existing)

Screenshots or recordings

No UI changes.

Release note

  • No user-facing change. Release note is NONE.
  • User-facing change. Release note is included below.
NONE

Checklist

  • The PR title uses at least one approved prefix: [Feat], [Fix], [UI], [Docs], [Refactor], [Build], or [Chore]
  • The summary explains both what changed and why
  • Validation reflects the commands actually run for this PR
  • Architecture impact is described and references any touched invariants
  • Cross-layer changes are explicitly justified
  • The release note block is accurate

… pre-resolution

Extract SSRF protection from auto-extract.ts into a shared net/ module:

- ssrf-guard.ts: numeric IPv4/IPv6 range checks covering all RFC 1918,
  link-local, CGNAT, benchmark, and reserved ranges; IPv4-mapped IPv6
  detection; DNS pre-resolution to block rebinding attacks
- safe-fetch.ts: unified HTTPS-only fetch with SSRF guard, size limit,
  and timeout — replaces ad-hoc fetch logic in both auto-extract.ts
  and artifact-handlers.ts

The previous string-prefix approach had false positives (blocking
10.cdn.example.com) and false negatives (IPv6-mapped IPv4 bypass,
DNS rebinding). This replaces it with proper numeric IP parsing via
node:net isIP() and pre-fetch DNS resolution via node:dns/promises.

Adds 56 tests (49 ssrf-guard + 7 safe-fetch).
@github-actions
Copy link
Copy Markdown
Contributor

Hi @samzong,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

@samzong samzong merged commit 85990de into main Mar 27, 2026
7 checks passed
@samzong samzong deleted the fix/ssrf-private-host-check branch March 29, 2026 14:10
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