Skip to content

fix(security): resolve IPv6-mapped IPv4 bypass in SSRF protection#2176

Merged
Priyanshu-byte-coder merged 2 commits into
Priyanshu-byte-coder:mainfrom
VIDYANKSHINI:fix/ssrf-ipv6-protection
Jun 7, 2026
Merged

fix(security): resolve IPv6-mapped IPv4 bypass in SSRF protection#2176
Priyanshu-byte-coder merged 2 commits into
Priyanshu-byte-coder:mainfrom
VIDYANKSHINI:fix/ssrf-ipv6-protection

Conversation

@VIDYANKSHINI
Copy link
Copy Markdown
Contributor

Summary

Fixed a critical SSRF vulnerability bypass involving IPv6-mapped IPv4 addresses and AAAA-only hosts, and patched an underlying 32-bit signed integer overflow bug in the IP evaluation logic.

Closes #2151


Type of Change

  • Bug fix
  • Security patch
  • New feature
  • Documentation update
  • Refactor / code cleanup

Changes Made

  • Bitwise Signed Integer Overflow Fix: Patched ipToNumber to return a 32-bit unsigned integer (via >>> 0). Previously, calculating 192 << 24 resulted in a negative number, allowing internal IPs like 192.168.x.x to silently bypass the bounds check.
  • IPv6 Mapped IPv4: Added logic to extract the IPv4 portion from IPv6-mapped addresses (e.g., ::ffff:192.168.1.1) and validate it normally.
  • IPv6 Loopback & Link-local Protection: Explicitly blocked common IPv6 private networks (::1, ::, fe80::, fc00::, fd00::).
  • AAAA Record Validation: Enhanced isSafeUrl to resolve both A and AAAA records. If any resolved IP points to a private/internal network, the request is blocked.
  • Expanded Test Coverage: Added comprehensive Vitest test cases mocking dns.resolve to verify behavior for IPv6, mapped IPv4, and public/private resolutions.

How to Test

  1. Run npm run test locally and verify that the ssrf-protection.test.ts suite passes, including all the new isSafeUrl test cases.
  2. Confirm that public domains continue to resolve correctly while resolving an AAAA record like ::ffff:169.254.169.254 returns false.

Screenshots (if UI change)

N/A


Checklist

  • Linked issue in summary
  • npm run lint passes locally
  • No TypeScript errors (npm run type-check)
  • Self-reviewed the diff
  • Added/updated tests if applicable

Copilot AI review requested due to automatic review settings June 7, 2026 14:30
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 7, 2026

@VIDYANKSHINI is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:security GSSoC type bonus: security (+20 pts) type:testing GSSoC type bonus: tests (+10 pts) labels Jun 7, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 7, 2026

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR strengthens SSRF defenses by improving IP parsing/private-network detection (including IPv6 cases) and expanding isSafeUrl DNS resolution to cover both A and AAAA records, with new tests added around these behaviors.

Changes:

  • Harden IPv4 parsing and private-IP detection (incl. IPv6-mapped IPv4 handling and invalid format blocking).
  • Update isSafeUrl to resolve both A and AAAA DNS records and reject more localhost bypass patterns.
  • Add Vitest coverage for isSafeUrl using mocked DNS resolution.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
test/ssrf-protection.test.ts Adds unit tests for isSafeUrl, including protocol filtering and private/public IP outcomes via DNS mocks.
src/lib/ssrf-protection.ts Enhances IP parsing/private detection and extends isSafeUrl to check both IPv4 and IPv6 DNS records.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +19
const parts = ip.split(".");
if (parts.length !== 4) return NaN;
const numParts = parts.map(Number);
if (numParts.some(isNaN)) return NaN;
return ((numParts[0] << 24) | (numParts[1] << 16) | (numParts[2] << 8) | numParts[3]) >>> 0;
Comment thread src/lib/ssrf-protection.ts Outdated
Comment on lines +65 to +68
// Allow basic bypassing localhost blocks if they try to bypass resolution completely
if (hostname === "localhost" || hostname === "0.0.0.0" || hostname === "[::1]") {
return false;
}
Comment on lines +70 to 84
const addresses: string[] = [];

try {
const aRecords = await resolve(hostname, "A");
if (Array.isArray(aRecords)) addresses.push(...(aRecords as string[]));
} catch {}

try {
const aaaaRecords = await resolve(hostname, "AAAA");
if (Array.isArray(aaaaRecords)) addresses.push(...(aaaaRecords as string[]));
} catch {}

if (addresses.length === 0) {
return false;
}
Comment thread src/lib/ssrf-protection.ts Outdated
Comment on lines +65 to +66
// Allow basic bypassing localhost blocks if they try to bypass resolution completely
if (hostname === "localhost" || hostname === "0.0.0.0" || hostname === "[::1]") {
Comment thread test/ssrf-protection.test.ts Outdated
Comment on lines +3 to +9
import dns from "dns";

vi.mock("dns", () => ({
default: {
resolve: vi.fn(),
},
}));
Comment thread test/ssrf-protection.test.ts Outdated
Comment on lines +83 to +86
mockResolve.mockImplementation((hostname: string, rrtype: string, cb: Function) => {
if (rrtype === "A") cb(null, ["8.8.8.8"]);
else cb(new Error("ENOTFOUND"));
});
Comment thread test/ssrf-protection.test.ts Outdated
import { validateUrlBasic } from "../src/lib/ssrf-protection";
import { describe, it, expect } from "vitest";
import { validateUrlBasic, isSafeUrl } from "../src/lib/ssrf-protection";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
@Priyanshu-byte-coder Priyanshu-byte-coder added gssoc:approved GSSoC: PR approved for scoring level2 GSSoC Level 2 - Medium complexity (25 points) quality:clean GSSoC: Clean quality multiplier (×1.2) labels Jun 7, 2026
@Priyanshu-byte-coder Priyanshu-byte-coder merged commit 77b1387 into Priyanshu-byte-coder:main Jun 7, 2026
12 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 7, 2026

🎉 Merged! Thanks for contributing to DevTrack.

If the project has been useful to you, a ⭐ star on the repo is the easiest way to support it — it helps DevTrack get discovered by more developers.

Keep an eye on open issues for your next contribution!

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

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution level2 GSSoC Level 2 - Medium complexity (25 points) quality:clean GSSoC: Clean quality multiplier (×1.2) type:bug GSSoC type bonus: bug fix type:security GSSoC type bonus: security (+20 pts) type:testing GSSoC type bonus: tests (+10 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(security): IPv6-mapped IPv4 addresses bypass private IP check in SSRF protection

3 participants