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.

Prevention & Best Practices

1. Defense in Depth for SSRF

Never rely solely on IP validation. Implement multiple layers:

// Layer 1: Validate the input IP/hostname
// Layer 2: Resolve the hostname and validate the resolved IP
// Layer 3: Use network-level controls (firewall rules, VPC configuration)
// Layer 4: Limit outbound connectivity from your application

2. Prefer Allowlists Over Blocklists

Instead of blocking known-bad IPs, consider allowing only known-good destinations:

const ALLOWED_HOSTS = ['api.stripe.com', 'api.github.com'];

function isAllowedDestination(hostname) {
  return ALLOWED_HOSTS.includes(hostname);
}

3. Validate After DNS Resolution

Always validate the resolved IP address, not just the user-provided string:

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

async function safeResolve(hostname) {
  const addresses = await dns.resolve4(hostname);
  for (const ip of addresses) {
    const addr = new Address4(ip);
    if (isPrivateOrReserved(addr)) {
      throw new Error('Resolved to blocked IP range');
    }
  }
  return addresses[0];
}

4. Keep Dependencies Updated

Use automated tools to monitor for vulnerable dependencies:

# npm audit for vulnerability scanning
npm audit

# Use tools like Trivy for comprehensive scanning
trivy fs --scanners vuln .

5. Use npm Overrides for Transitive Dependencies

When a vulnerability exists in a transitive dependency, npm overrides provide a clean solution:

{
  "overrides": {
    "vulnerable-package": "^fixed.version"
  }
}

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.

References

Frequently Asked Questions

What is SSRF via IP parsing inconsistency?

It's a vulnerability where different components interpret IP addresses differently, allowing attackers to craft addresses that bypass security checks but resolve to restricted targets.

How do you prevent IP parsing SSRF in Node.js?

Use libraries that parse IP addresses consistently with system resolvers, validate resolved addresses (not just input strings), and implement allowlists rather than blocklists where possible.

What CWE is SSRF?

CWE-918 (Server-Side Request Forgery) covers vulnerabilities where an attacker can make a server perform requests to unintended locations.

Is IP blocklisting enough to prevent SSRF?

No, blocklisting alone is insufficient because parsing inconsistencies, DNS rebinding, and IPv6 representations can bypass blocklists. Defense-in-depth with network segmentation is essential.

Can static analysis detect IP parsing SSRF?

Yes, tools like Trivy can detect known vulnerable library versions, and SAST tools can identify patterns where user input flows into HTTP request targets without proper validation.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #52

Related Articles

high

How NO_PROXY bypass via crafted URL happens in Node.js axios and how to fix it

A high-severity vulnerability (CVE-2026-42043) in the axios HTTP client library allowed attackers to bypass NO_PROXY environment variable restrictions using specially crafted URLs. This could route sensitive internal traffic through attacker-controlled proxy servers. The fix upgrades axios from 1.13.6 to 1.18.0, which includes a rewritten proxy resolution mechanism using `proxy-from-env` v2.1.0 and the `https-proxy-agent` package.

high

How Server-Side Request Forgery (SSRF) happens in Node.js through inconsistent IP address parsing and how to fix it

A high-severity Server-Side Request Forgery (SSRF) vulnerability (CVE-2026-69192) was discovered in the ip-address package version 10.2.0, where inconsistent IP address parsing allowed attackers to bypass trust boundaries and access internal resources. The fix upgrades ip-address from 10.2.0 to 10.3.1 across the dependency tree, with explicit pinning in package.json and strategic version management in bun.lock to prevent both direct and transitive exploitation paths.

critical

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

A critical Server-Side Request Forgery (SSRF) vulnerability was discovered in `libraries/microworlds/video.js` where the `VideoCanvasWrapper.loadVideo()` function passed user-controlled URLs directly to `fetch()` without any validation. An attacker could exploit this by supplying URLs pointing to internal services, localhost endpoints, or malicious external servers. The fix introduces strict URL parsing and protocol validation before any network request is made.

high

How IP Address Parsing Inconsistency Happens in Node.js and How to Fix It

CVE-2026-69192 revealed a critical inconsistency in the `ip-address` npm package where the `Address4` class decoded leading-zero octets as decimal while standard DNS resolvers interpreted them as octal, creating a trust-boundary bypass and SSRF attack vector. The fix upgrades `ip-address` from version 10.2.0 to 10.3.1 in the CanvaLight plugin, correcting the parsing behavior to match resolver expectations.

high

How Message-Level Raw Option Bypass happens in Node.js Nodemailer and how to fix it

A high-severity vulnerability in Nodemailer (GHSA-p6gq-j5cr-w38f) allowed attackers to bypass the `disableFileAccess` and `disableUrlAccess` security controls by using the message-level `raw` option, enabling arbitrary file reads and full-response SSRF in delivered emails. The fix upgrades Nodemailer from version 6.10.1 to 9.0.1, closing this bypass at the library level. This is especially critical for applications that allow any user-influenced content to flow into email composition.

high

How Unauthenticated Denial of Service happens in React Router and how to fix it

CVE-2026-55685 is a high-severity Denial of Service vulnerability in React Router's `@remix-run/server-runtime` that allows unauthenticated attackers to exhaust server resources by sending crafted requests to the manifest endpoint. The fix upgrades `react-router` from version 7.17.0 to 7.18.0, which tightens handling of untrusted input in route matching logic. Developers using any React Router 7.x application with server-side rendering should apply this patch immediately.