Back to Blog
high SEVERITY6 min read

How Octal IP Address Parsing Inconsistency Enables SSRF in Node.js and How to Fix It

A critical parsing inconsistency in the `ip-address` npm package (version 10.2.0) allowed attackers to bypass SSRF protections by exploiting how leading-zero octets are interpreted differently—decimal by the library versus octal by system resolvers. This vulnerability (CVE-2026-69192) was fixed by upgrading to version 10.3.1 using an npm override, ensuring consistent IP address validation across the application.

O
By Orbis AppSec
Published August 11, 2026Reviewed August 11, 2026

Answer Summary

CVE-2026-69192 is a high-severity SSRF vulnerability in the Node.js `ip-address` package (versions before 10.3.1) caused by inconsistent parsing of leading-zero IP octets—the library interprets them as decimal while system resolvers treat them as octal (CWE-918). This mismatch allows attackers to craft IP addresses that appear safe to validation but resolve to internal/blocked addresses. The fix involves upgrading `ip-address` to 10.3.1 via npm overrides to ensure consistent octal-aware parsing.

Vulnerability at a Glance

cweCWE-918
fixUpgrade ip-address from 10.2.0 to 10.3.1 using npm overrides
riskAttackers can bypass IP blocklists to access internal services or restricted endpoints
languageJavaScript/Node.js
root causeip-address library decoded leading-zero octets as decimal while resolvers decode them as octal
vulnerabilityServer-Side Request Forgery (SSRF) via IP Address Parsing Inconsistency

Introduction

In a Node.js application's dependency tree, we discovered a high-severity SSRF vulnerability lurking in the ip-address package at version 10.2.0. The package-lock.json file locked this vulnerable version, which handles IP address parsing and validation—a critical security boundary for any application that makes outbound requests based on user input.

The vulnerability, tracked as CVE-2026-69192, exploits a subtle but dangerous inconsistency: when you write an IP address like 0177.0.0.1, the ip-address library's Address4 class interprets those leading zeros as decimal notation, seeing it as 177.0.0.1. But when your operating system's resolver processes that same address, it interprets the leading zero as octal notation—meaning 0177 becomes 127 in decimal. The result? Your validation says "safe external IP," but the actual request goes to 127.0.0.1—localhost.

This matters for any developer using IP validation to protect against SSRF attacks, which is essentially everyone building applications that fetch URLs or connect to user-specified addresses.

The Vulnerability Explained

How Octal IP Parsing Works (And Doesn't)

IP addresses have a lesser-known feature: octets with leading zeros can be interpreted as octal numbers. This is a POSIX standard behavior that most system resolvers follow:

0177.0.0.1    Octal: 127.0.0.1 (localhost!)
0300.0.0.1    Octal: 192.0.0.1
010.0.0.1     Octal: 8.0.0.1

The vulnerable ip-address version 10.2.0 ignored this convention entirely. Its Address4 class parsed all octets as decimal, regardless of leading zeros:

// How ip-address 10.2.0 parsed addresses (simplified)
// Input: "0177.0.0.1"
// Library sees: 177.0.0.1 (decimal interpretation)
// System resolver sees: 127.0.0.1 (octal interpretation)

The Attack Scenario

Imagine your application has SSRF protection that blocks requests to internal IP ranges:

const { Address4 } = require('ip-address');

function isBlockedIP(ipString) {
  const addr = new Address4(ipString);
  // Block localhost, private ranges, etc.
  if (addr.isInSubnet(new Address4('127.0.0.0/8'))) return true;
  if (addr.isInSubnet(new Address4('10.0.0.0/8'))) return true;
  if (addr.isInSubnet(new Address4('192.168.0.0/16'))) return true;
  return false;
}

// Attacker submits: "0177.0.0.1"
isBlockedIP("0177.0.0.1");  // Returns FALSE (sees 177.0.0.1)
// But when the request is made...
fetch("http://0177.0.0.1/admin/secrets");  // Actually hits 127.0.0.1!

An attacker could use this to:
- Access internal admin panels on localhost
- Reach cloud metadata endpoints (like AWS's 169.254.169.254 via 0251.0376.0251.0376)
- Probe internal network services that should be unreachable
- Exfiltrate data from internal APIs

Real-World Impact

This application uses Firebase Admin SDK and Stripe—both of which handle sensitive data. If any component validates user-supplied URLs or IP addresses before making requests (common in webhook validation, proxy functionality, or URL preview features), this parsing inconsistency could allow attackers to bypass those protections and access internal services or sensitive endpoints.

The Fix

The fix implemented in this PR is elegant in its simplicity: upgrade the ip-address package from 10.2.0 to 10.3.1, where the maintainers corrected the octal parsing behavior.

What Changed in package.json

// Before
{
  "dependencies": {
    "firebase-admin": "^13.10.0",
    "stripe": "^22.3.0",
    "supercompress-proxy": "^0.5.17"
  }
}

// After
{
  "dependencies": {
    "firebase-admin": "^13.10.0",
    "stripe": "^22.3.0",
    "supercompress-proxy": "^0.5.17"
  },
  "overrides": {
    "ip-address": "10.3.1"
  }
}

Why Use npm Overrides?

The ip-address package isn't a direct dependency—it's a transitive dependency somewhere in the dependency tree (likely through supercompress-proxy or another package). The overrides field in package.json forces npm to use version 10.3.1 regardless of what version the parent packages request.

What Changed in package-lock.json

// Before
"node_modules/ip-address": {
  "version": "10.2.0",
  "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
  "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="
}

// After
"node_modules/ip-address": {
  "version": "10.3.1",
  "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.3.1.tgz",
  "integrity": "sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g=="
}

How Version 10.3.1 Fixes the Issue

The patched version now correctly interprets leading-zero octets as octal, matching the behavior of system resolvers:

// ip-address 10.3.1 behavior
const { Address4 } = require('ip-address');

// Input: "0177.0.0.1"
// Now correctly parsed as: 127.0.0.1 (octal interpretation)
// Validation and resolution are now CONSISTENT

This means your SSRF blocklist will correctly identify 0177.0.0.1 as localhost and block the request before it's made.

Key Takeaways

  • Octal IP notation is a real attack vector: The obscure 0177.0.0.1 syntax can bypass naive IP validation in any language where the validation library and system resolver disagree on interpretation.

  • Transitive dependencies carry risk: The ip-address vulnerability wasn't in direct dependencies but hidden in the dependency tree—npm overrides is the correct mechanism to force upgrades.

  • SSRF protection requires consistency: Your validation logic must interpret IP addresses exactly as the component making the actual request will interpret them.

  • The supercompress-proxy dependency path (or similar) pulled in the vulnerable ip-address version—always audit your full dependency tree, not just direct dependencies.

  • Version 10.3.1 specifically addresses octal parsing: This isn't just a general security update; it's a targeted fix for the decimal-vs-octal interpretation mismatch.

How Orbis AppSec Detected This

  • Source: User-controlled URL or IP address input flowing through the application's request handling
  • Sink: The ip-address library's Address4 class used for IP validation before outbound requests
  • Missing control: Consistent octal-aware IP parsing that matches system resolver behavior
  • CWE: CWE-918 (Server-Side Request Forgery)
  • Fix: Upgraded ip-address from 10.2.0 to 10.3.1 via npm overrides to ensure consistent IP address interpretation

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-69192 demonstrates how subtle parsing inconsistencies can completely undermine security controls. The ip-address library's decimal interpretation of leading-zero octets, while technically valid in isolation, created a dangerous mismatch with how operating systems actually resolve these addresses.

The fix was straightforward—a version upgrade via npm overrides—but the vulnerability itself highlights the importance of understanding the full data flow in your applications. When validating IP addresses for security purposes, ensure your validation library interprets addresses exactly as the downstream components will.

For Node.js developers: audit your dependencies for ip-address versions below 10.3.1, and consider implementing defense-in-depth SSRF protections that don't rely solely on pre-request IP validation.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #52

Related Articles

medium

How gitlab.bandit.B501 happens in Python and how to fix it

The `proverbia-scraper.py` script disabled TLS certificate verification on its `requests.get()` call and silenced the resulting security warnings, exposing the scraper to man-in-the-middle attacks. The fix removes the `verify=False` flag and the warning suppression, restoring proper certificate validation while keeping the existing 30-second timeout intact.

high

How Server-Side Request Forgery (SSRF) happens in Go HTTP handlers and how to fix it

A Server-Side Request Forgery (SSRF) vulnerability was discovered in `internal/web/controller/server.go` where the `applySubTemplate` endpoint accepted arbitrary URLs from user input and passed them directly to `serverService.ApplySubTemplateFromGithub()` without any host validation. An attacker could exploit this to make the server issue HTTP requests to internal network resources, cloud metadata endpoints, or redirect-controlled destinations. The fix introduces a strict allowlist that restrict

critical

How SSRF via Vulnerable Dependency Versions Happens in Node.js and How to Fix It

A permissive semver range in `package.json` allowed npm to install axios versions vulnerable to SSRF (CVE-2024-39338). By bumping the minimum version from `^1.6.0` to `^1.7.4`, all downstream consumers of this SDK are now protected from server-side request forgery attacks. This critical fix required changing just one line in the dependency manifest.

critical

How Server-Side Request Forgery happens in Python FastAPI and how to fix it

A critical Server-Side Request Forgery (SSRF) vulnerability was discovered in app.py where the `/parse` and `/parse-video` endpoints accepted user-supplied URLs with only substring validation. The application checked if 'doubao.com' appeared anywhere in the URL string, allowing attackers to bypass this check and access internal services, cloud metadata endpoints, or scan the internal network. The fix implemented proper hostname parsing with an allowlist of legitimate domains.

critical

How Server-Side Request Forgery happens in Node.js maintenance scripts and how to fix it

A critical Server-Side Request Forgery (SSRF) vulnerability was discovered in `maintenance/getImages.js`, where the `getImage()` function passed database-sourced URLs directly to `axios.get()` without any validation. An attacker who could modify the elements database could redirect these requests to internal network resources — including AWS cloud metadata endpoints — potentially exposing IAM credentials and other sensitive infrastructure data. The fix introduces a strict URL allowlist that limi

high

How SSRF via inconsistent IP address parsing happens in Node.js dependencies and how to fix it

A high-severity flaw (CVE-2026-69192) in the widely-used `ip-address` npm package meant that IP strings could be parsed inconsistently compared to the OS resolver and Node's own networking stack — letting an attacker slip a private/loopback address past an allowlist that used `Address4`/`Address6` for validation. This PR pins and upgrades `ip-address` from `10.1.0` to `10.3.1` in both `package.json` (via `overrides`) and `package-lock.json`, eliminating the parser divergence across the whole dep