Skip to content

feat(security): add SSRF URL validation and private IP protection#546

Open
Namraa310806 wants to merge 1 commit into
FireFistisDead:masterfrom
Namraa310806:fix/ssrf-url-validation-hardening
Open

feat(security): add SSRF URL validation and private IP protection#546
Namraa310806 wants to merge 1 commit into
FireFistisDead:masterfrom
Namraa310806:fix/ssrf-url-validation-hardening

Conversation

@Namraa310806

@Namraa310806 Namraa310806 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR introduces SSRF protection utilities for validating externally supplied URLs before processing.

The implementation adds multiple layers of validation to reduce the risk of Server-Side Request Forgery (SSRF) attacks and strengthen URL handling security.

Changes Made

URL Validation

  • Added HTTPS-only URL enforcement.
  • Added URL parsing validation.
  • Added hostname normalization.
  • Added trailing-dot normalization.
  • Added IDN/Punycode normalization using domainToASCII().

Host Allowlist Protection

  • Added strict hostname allowlist validation.
  • Prevented hostname suffix bypass attempts through normalized label comparison.
  • Restricted accepted domains to approved Supabase host suffixes.

DNS Validation

  • Added DNS resolution before request execution.

  • Added support for both:

    • IPv4 (A records)
    • IPv6 (AAAA records)

Private Network Protection

Added blocking for private/internal address ranges:

IPv4

  • 127.0.0.0/8
  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16
  • 169.254.0.0/16

IPv6

  • ::1
  • fc00::/7
  • fe80::/10

Redirect Safety Utilities

Added reusable helpers for validating redirect destinations before following them.

Error Handling

Introduced a dedicated:

SSRFValidationError

for safe and consistent validation failures.

Security Impact

These changes improve protection against:

  • SSRF attacks targeting internal services.
  • Localhost access attempts.
  • Private network probing.
  • Link-local address access.
  • Basic hostname validation bypass techniques.
  • IDN hostname normalization issues.

Files Added / Modified

  • src/utils/ssrfValidation.js

Testing

Validated:

  • Allowed Supabase hostnames.
  • Invalid hostnames.
  • IPv4 private range detection.
  • IPv6 private range detection.
  • URL parsing failures.
  • HTTPS enforcement.

Notes

This PR focuses on introducing reusable SSRF validation utilities and supporting infrastructure. Additional route-level integration and validation coverage may be implemented separately where required.

FIxes: #498

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced security for remote PDF processing with Server-Side Request Forgery (SSRF) protection. The system now validates URLs and redirect targets before fetching remote files, enforces HTTPS-only connections, blocks requests to private/internal IP addresses, and implements stricter hostname allowlisting.
  • Tests

    • Added comprehensive SSRF validation test coverage including URL validation, redirect handling, IP privacy detection, and security bypass attempt scenarios.

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

@Namraa310806 is attempting to deploy a commit to the firefistisdead's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds src/utils/ssrfValidation.js implementing hostname allowlisting, private IPv4/IPv6 CIDR range blocking, DNS pre-resolution, and a manual redirect validator. The /process-from-url handler in server.js is rewired to use these utilities with redirects disabled and explicit 403/502 responses. Test fixtures and SSRF unit tests are also added.

Changes

SSRF Defense-in-Depth

Layer / File(s) Summary
SSRF validation module
src/utils/ssrfValidation.js
Adds SSRFValidationError, hostname normalization and allowlist matching against ALLOWED_HOST_SUFFIXES, IPv4 and IPv6 CIDR private-range detection, DNS pre-resolution via Promise.allSettled, validateURLForSSRF, validateRedirectForSSRF, and createSSRFSafeAxiosConfig (sets maxRedirects: 0). All symbols exported via module.exports.
/process-from-url handler rewiring
server.js
Imports the three SSRF helpers; removes the old inline https: and .endsWith hostname checks; replaces the download block with an SSRF-validated fetch using disabled auto-redirects, manual Location header validation via validateRedirectForSSRF, and explicit 403/502 responses for disallowed or missing redirect targets.
Test suite updates
server.test.js
Adds dns.promises.resolve4/resolve6 stubs (with matching restores) to existing protocol-relative and whitespace-trimmed URL tests; adds a new SSRF Validation describe block covering URL/redirect rejection, allowlist rules, trailing-dot bypass attempts, and private vs. public IPv4/IPv6 detection.

Test User Data Update

Layer / File(s) Summary
users.json test fixture
src/data/users.json
Replaces trailing user records with new testuser/testuser2 email entries and updated hashed password values.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant processFromUrl as /process-from-url
  participant validateURLForSSRF
  participant dns as dns.promises
  participant axios

  Client->>processFromUrl: POST {url}
  processFromUrl->>validateURLForSSRF: url string
  validateURLForSSRF->>validateURLForSSRF: parse, enforce https:, check allowlist
  validateURLForSSRF->>dns: resolve4(hostname) + resolve6(hostname)
  dns-->>validateURLForSSRF: IP addresses
  validateURLForSSRF->>validateURLForSSRF: reject private IPs
  validateURLForSSRF-->>processFromUrl: {url, hostname, ips} or SSRFValidationError

  processFromUrl->>axios: GET url (maxRedirects:0)
  alt 3xx redirect
    axios-->>processFromUrl: 3xx + Location header
    processFromUrl->>validateURLForSSRF: Location URL (via validateRedirectForSSRF)
    validateURLForSSRF-->>processFromUrl: allowed or 403
    processFromUrl->>axios: GET redirect URL
    axios-->>processFromUrl: PDF buffer
  else no Location header
    processFromUrl-->>Client: 502
  else direct 2xx
    axios-->>processFromUrl: PDF buffer
    processFromUrl-->>Client: pipeline result
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • FireFistisDead/pdf-qa-bot#403: Modifies the same /process-from-url SSRF hostname validation logic (allowlisting, normalization), which this PR supersedes by extracting those checks into src/utils/ssrfValidation.js and adding IP/redirect validation.
  • FireFistisDead/pdf-qa-bot#327: Introduces the /process-from-url route and PDF download pipeline that this PR rewires with the new SSRF-safe fetching flow.

Suggested labels

type:security, feature, backend, level:advanced, type:testing

Poem

🐇 Hop hop, no sneaky redirect shall pass,
Private IPs blocked like shadows in grass,
DNS resolved before the fetch is made,
Each CIDR range checked, each redirect weighed.
The bunny stands guard at the URL gate —
No SSRF bypass gets through, friend — too late! 🔒

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: adding SSRF URL validation and private IP protection utilities.
Description check ✅ Passed The description is comprehensive, covering summary, changes made, security impact, files modified, testing, and notes. All template sections are addressed with substantial detail.
Linked Issues check ✅ Passed The PR fully implements the defense-in-depth SSRF protections required by issue #498: DNS resolution validation, private IP blocking (IPv4/IPv6), redirect validation, and hostname allowlist enforcement.
Out of Scope Changes check ✅ Passed Changes in server.js and server.test.js integrate the SSRF utilities into the /process-from-url endpoint; users.json test data updates support testing. All changes align with issue #498 objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added backend Express or API gateway work bug Something isn't working enhancement New feature or request feature A new feature or improvement fix A targeted fix or cleanup frontend Frontend-related work gssoc:approved invalid This doesn't seem right rag-service FastAPI / model service work type:security type:testing labels Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
server.js (1)

28-28: 💤 Low value

Remove unused import createSSRFSafeAxiosConfig.

createSSRFSafeAxiosConfig is imported but never used. The axios calls at lines 1325 and 1340 manually set maxRedirects: 0 instead of using this helper.

Either use the helper for consistency or remove the unused import.

♻️ Suggested fix
-const { validateURLForSSRF, validateRedirectForSSRF, createSSRFSafeAxiosConfig } = require("./src/utils/ssrfValidation");
+const { validateURLForSSRF, validateRedirectForSSRF } = require("./src/utils/ssrfValidation");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server.js` at line 28, Remove the unused `createSSRFSafeAxiosConfig` function
from the destructuring import in the require statement at the top of server.js
(where validateURLForSSRF and validateRedirectForSSRF are imported). This
function is not used anywhere in the file, and the axios calls that manually set
maxRedirects: 0 should either be refactored to use this helper for consistency
or left as-is with the import removed.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server.js`:
- Around line 1325-1356: The redirect handling code in the conditional check for
status codes 300-399 is unreachable because axios's default validateStatus
configuration rejects any status outside 200-299 and throws an error before
returning. To fix this, add a validateStatus option to the first axios.get call
(the one making the initial download request with downloadUrl.toString()) that
accepts 3xx responses, either by setting validateStatus: (status) => status <
400, or by using the already-imported createSSRFSafeAxiosConfig helper function
which includes this configuration. This will allow the dlResponse to return with
3xx status codes so the redirect validation logic can actually execute.

In `@src/utils/ssrfValidation.js`:
- Around line 10-16: The PRIVATE_IPV4_RANGES array in the SSRF validation is
missing four critical IPv4 ranges needed for comprehensive protection: 0.0.0.0/8
(this network), 100.64.0.0/10 (Carrier-grade NAT), 224.0.0.0/4 (Multicast), and
240.0.0.0/4 (Reserved). Add these four ranges to the PRIVATE_IPV4_RANGES array
with their corresponding start addresses and prefix values, ensuring the
0.0.0.0/8 range is included as it is particularly important for preventing
bypass attacks on certain operating systems.

---

Nitpick comments:
In `@server.js`:
- Line 28: Remove the unused `createSSRFSafeAxiosConfig` function from the
destructuring import in the require statement at the top of server.js (where
validateURLForSSRF and validateRedirectForSSRF are imported). This function is
not used anywhere in the file, and the axios calls that manually set
maxRedirects: 0 should either be refactored to use this helper for consistency
or left as-is with the import removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bd76ab22-da02-4a36-85bc-9dc340624beb

📥 Commits

Reviewing files that changed from the base of the PR and between 5590b87 and 12c4fe9.

📒 Files selected for processing (4)
  • server.js
  • server.test.js
  • src/data/users.json
  • src/utils/ssrfValidation.js

Comment thread server.js
Comment thread src/utils/ssrfValidation.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Express or API gateway work bug Something isn't working enhancement New feature or request feature A new feature or improvement fix A targeted fix or cleanup frontend Frontend-related work gssoc:approved invalid This doesn't seem right rag-service FastAPI / model service work type:security type:testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Strengthen SSRF Defenses in /process-from-url by Validating Redirect Targets and Resolved IP Addresses

1 participant