Back to Blog
high SEVERITY8 min read

How IP Address Parsing Inconsistencies Cause SSRF and Trust-Boundary Bypass in Node.js Applications

The `ip-address` library version 10.2.0 contained a critical parsing inconsistency where the `Address4` decoder interpreted leading-zero octets as decimal numbers, while most DNS resolvers and network systems interpreted them as octal. This mismatch allowed attackers to bypass IP-based access controls and SSRF filters. Upgrading to version 10.3.1 fixes this vulnerability by aligning the library's parsing behavior with standard resolver behavior.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published August 28, 2026•Reviewed August 28, 2026

Answer Summary

CVE-2026-69192 is a Server-Side Request Forgery (SSRF) vulnerability in the Node.js `ip-address` library (versions before 10.3.1) caused by inconsistent IP address parsing. The `Address4` class decoded leading-zero octets as decimal while DNS resolvers decode them as octal, allowing attackers to bypass IP-based trust boundaries and access controls. The fix, implemented in version 10.3.1, corrects the octal parsing logic to match standard resolver behavior, eliminating the parsing discrepancy.

Vulnerability at a Glance

cweCWE-1025 (Comparison Using Wrong Factors), CWE-918 (Server-Side Request Forgery)
fixUpdate ip-address from 10.2.0 to 10.3.1 to align parsing behavior with standard resolver implementations
riskAttackers can bypass IP-based access controls and SSRF filters by crafting specially formatted IP addresses
languageJavaScript/Node.js
root causeAddress4 decoder treats leading-zero octets as decimal while resolvers treat them as octal
vulnerabilityIP Address Parsing Inconsistency / SSRF via Octal Bypass

How IP Address Parsing Inconsistencies Cause SSRF and Trust-Boundary Bypass in Node.js Applications

Understanding the Vulnerability

In many Node.js applications, the ip-address library is used to parse, validate, and work with IPv4 addresses. The library's Address4 class is commonly relied upon to validate IP addresses before making network requests or enforcing access controls. However, version 10.2.0 and earlier contained a subtle but critical flaw: the library decoded leading-zero octets as decimal numbers, while DNS resolvers and most network systems interpreted them as octal.

This inconsistency created a security gap where an attacker could craft an IP address that the ip-address library would classify as safe (matching an allowlist), but which would be interpreted by the actual resolver as a completely different IP address—potentially one that should have been blocked.

The Vulnerability Explained

The Parsing Inconsistency

Consider this example:

  • Input IP: 192.168.001.1
  • ip-address 10.2.0 parses it as: 192.168.1.1 (treating 001 as decimal)
  • DNS resolver interprets it as: 192.168.1.1 in standard mode, but 192.168.1.1 in some systems, or octal 192.168.001.1 = 192.168.1.1

But here's the dangerous case:

  • Input IP: 127.000.000.001
  • ip-address 10.2.0 parses it as: 127.0.0.1 (decimal interpretation of leading zeros)
  • DNS resolver interprets it as: 127.0.0.1 (octal interpretation: 000 = 0 in octal, 001 = 1 in octal)

While this example resolves to the same address, the vulnerability becomes critical when:

  • Input IP: 192.168.0177.1 (where 0177 is octal for 127)
  • ip-address 10.2.0 parses it as: 192.168.177.1 (treating 0177 as decimal)
  • DNS resolver interprets it as: 192.168.127.1 (treating 0177 as octal)

An attacker could submit 192.168.0177.1 to an application that uses ip-address for validation. The application checks: "Is this in my blocklist?" The library says no, it's 192.168.177.1. But when the resolver actually processes the request, it interprets it as 192.168.127.1—potentially an internal address that should have been blocked.

How This Enables SSRF Attacks

Server-Side Request Forgery (SSRF) attacks occur when an attacker can trick a server into making requests to unintended destinations. IP-based allowlists and blocklists are a common defense:

// Vulnerable code pattern in applications using ip-address 10.2.0
const Address4 = require('ip-address').Address4;

const INTERNAL_IPS = ['127.0.0.1', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'];

function isAllowedIP(userProvidedIP) {
  try {
    const addr = new Address4(userProvidedIP);
    const normalizedIP = addr.toString(); // Uses decimal parsing

    // Check if normalized IP is in allowlist
    return INTERNAL_IPS.some(internal => normalizedIP.startsWith(internal));
  } catch (e) {
    return false;
  }
}

// Attacker submits: 127.000.000.001
// Library parses as: 127.0.0.1
// Allowlist check: PASSES (it's localhost)
// BUT if resolver behavior differs, actual request goes elsewhere

The attack flow:
1. Attacker provides a crafted IP like 192.168.0177.1
2. Application's ip-address library parses it as 192.168.177.1
3. Allowlist check passes because 192.168.177.1 isn't blocked
4. Application makes HTTP request to 192.168.0177.1
5. Resolver interprets 0177 as octal (127), resolving to 192.168.127.1
6. Request reaches an internal service that was supposed to be blocked

Real-World Impact

This vulnerability affects any Node.js application that:
- Uses ip-address library version 10.2.0 or earlier
- Implements IP-based access controls or SSRF prevention
- Makes HTTP requests based on user-provided IP addresses or URLs
- Runs in environments where DNS resolvers interpret octal notation

Affected applications could be vulnerable to:
- Internal service access: Bypassing firewall rules to access internal databases, caches, or APIs
- Metadata service attacks: On cloud platforms (AWS, GCP, Azure), accessing instance metadata services
- Local file access: Depending on the application's architecture
- Trust boundary bypass: Accessing services that should only be reachable internally

The Fix

The fix was implemented in ip-address version 10.3.1. The package upgrade corrected the octal parsing logic in the Address4 class to properly handle leading-zero octets according to standard resolver behavior.

What Changed

From the PR diff:

- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
- "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
+ "version": "10.3.1",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.3.1.tgz",
+ "integrity": "sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==",

The upgrade from 10.2.0 to 10.3.1 in both package.json and package-lock.json applies the security patch.

How the Fix Works

In version 10.3.1, the Address4 parser was corrected to:

  1. Properly detect octal notation: When an octet begins with 0 followed by digits, it's now correctly interpreted as octal (base 8) rather than decimal (base 10)
  2. Align with resolver behavior: The parsing now matches how DNS resolvers and network utilities interpret IP addresses
  3. Maintain backward compatibility: Valid, standard IP addresses (without leading zeros) continue to work exactly as before

Before (10.2.0):

Input: "192.168.0177.1"
Parsing: 192 . 168 . 0177(decimal=177) . 1
Result: "192.168.177.1"

After (10.3.1):

Input: "192.168.0177.1"
Parsing: 192 . 168 . 0177(octal=127) . 1
Result: "192.168.127.1"

Why This Matters

Now, when an attacker submits 192.168.0177.1, the ip-address library will correctly identify it as 192.168.127.1, and your allowlist/blocklist checks will work as intended. The parsing behavior is no longer a security liability—it aligns with what actually happens on the network.

Prevention & Best Practices

1. Keep Dependencies Updated

Regularly audit and update dependencies, especially security-critical libraries like ip-address. Use tools like npm audit to identify vulnerable versions:

npm audit
npm update ip-address

2. Don't Rely Solely on IP Validation

While IP-based access controls are useful, they should be one layer of defense:

// Good: Multiple validation layers
function isRequestAllowed(req) {
  // Layer 1: IP validation
  if (!isAllowedIP(req.ip)) return false;

  // Layer 2: Authentication
  if (!req.user) return false;

  // Layer 3: Authorization
  if (!req.user.canAccessResource(req.resource)) return false;

  return true;
}

3. Validate Against Actual Resolver Behavior

When implementing custom IP parsing, test against actual DNS resolvers:

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

async function validateIP(userIP) {
  try {
    // Parse with ip-address
    const addr = new Address4(userIP);

    // Verify against actual DNS resolution
    const resolved = await dns.resolve4(userIP);

    // Compare parsed vs resolved
    if (addr.toString() !== resolved[0]) {
      console.warn(`Mismatch: ${userIP} parsed as ${addr.toString()}, resolved as ${resolved[0]}`);
      return false; // Reject ambiguous IPs
    }

    return true;
  } catch (e) {
    return false;
  }
}

4. Use Static Analysis Tools

Enable security scanning in your CI/CD pipeline:

# Trivy scans for known vulnerable dependencies
trivy fs .

# npm audit checks for CVEs
npm audit

5. Follow OWASP Guidelines

  • OWASP A01:2021 – Broken Access Control: Implement proper access control, not just IP validation
  • OWASP A10:2021 – Server-Side Request Forgery (SSRF): Use allowlists, not blocklists; validate all URLs and IPs

6. Test Edge Cases

Include tests for IP addresses with leading zeros:

const Address4 = require('ip-address').Address4;

describe('IP Address Parsing', () => {
  it('should correctly parse octal notation', () => {
    const addr = new Address4('192.168.0177.1');
    expect(addr.toString()).toBe('192.168.127.1'); // Not 192.168.177.1
  });

  it('should reject ambiguous IPs', () => {
    // Your application logic should reject IPs with leading zeros
    // or verify them against actual resolver behavior
  });
});

Key Takeaways

  • Leading-zero octets in IP addresses are octal, not decimal: The ip-address library version 10.2.0 incorrectly treated them as decimal, creating a parsing mismatch with DNS resolvers and network systems.

  • This mismatch enables SSRF attacks: Attackers could craft IPs that pass your allowlist but resolve to blocked internal addresses, bypassing trust boundaries.

  • The fix aligns parsing with resolver behavior: Upgrading to ip-address 10.3.1 ensures the library interprets IPs the same way DNS resolvers do, eliminating the vulnerability.

  • IP validation alone is insufficient: Always use defense-in-depth with authentication, authorization, and multiple validation layers.

  • Regular dependency updates are critical: Vulnerabilities like this can be fixed with a simple version bump—but only if you keep your dependencies current.

How Orbis AppSec Detected This

Source: User-controlled URL or IP address input in network request functions

Sink: The Address4 class constructor and toString() method in the ip-address library (versions ≤10.2.0), which was used to validate IPs before making HTTP requests or enforcing access controls

Missing control: The ip-address library's parsing logic did not align with standard DNS resolver behavior for octal notation, creating an inconsistency that could be exploited

CWE: CWE-918 (Server-Side Request Forgery), CWE-1025 (Comparison Using Wrong Factors)

Fix: Upgrade ip-address from 10.2.0 to 10.3.1, which corrects the octal parsing logic to match standard resolver behavior

Orbis AppSec automatically detected this vulnerability through dependency scanning 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 inconsistencies in parsing logic can create serious security vulnerabilities. By treating leading-zero octets as decimal instead of octal, the ip-address library created a trust boundary bypass that could allow SSRF attacks. The fix in version 10.3.1 aligns the library's behavior with standard resolver implementations, eliminating the vulnerability.

As developers, we should:
1. Keep dependencies updated and monitor security advisories
2. Understand the libraries we use, especially those handling security-critical functions like IP validation
3. Implement defense-in-depth rather than relying on a single security control
4. Test edge cases and validate assumptions about how systems interpret data
5. Use automated scanning to catch known vulnerabilities before they reach production

By staying vigilant and maintaining current dependencies, you can prevent vulnerabilities like this from affecting your applications.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #46

Related Articles

high

axios 1.18.1 CVE-2026-101898: HTTP/2 Ignores proxy and lookup

A dependency upgrade moved `axios` from 1.18.1 to 1.20.0 to pick up the fix for CVE-2026-101898, in which proxy and DNS resolution settings supplied through axios request configuration were not applied on the HTTP/2 request path. Applications that rely on `config.proxy`, `HTTP_PROXY`/`NO_PROXY` environment variables, or a custom `lookup` function as an SSRF or egress control could have those controls silently skipped for HTTP/2 requests.

critical

Cloudflare Worker Reverse Proxy SSRF via String Concatenation

A Cloudflare Worker reverse proxy built its upstream request URL by string-concatenating an environment variable with the incoming request's pathname and search string, letting a crafted path or query redirect requests to attacker-chosen hosts. The fix replaces concatenation with the `URL` object's `pathname` and `search` setters, which normalize input against the configured origin instead of blindly appending it.

high

fast-uri 3.1.2 IDN Host Bypass: CVE-2026-13676 Upgrade

A dependency tree in this repository resolved `fast-uri` 3.1.2, a version affected by CVE-2026-13676, in which improper Unicode hostname canonicalization lets a crafted URI parse to one host while the HTTP client connects to another. Because `fast-uri` is what `ajv` uses to parse and resolve URIs for `format: "uri"` validation and `$ref` resolution, any host allowlist built on its parsed output could be bypassed. The fix upgrades the resolved copy to `fast-uri` 4.1.4 and pins it with an npm `ove

high

boardcards.js parseArgs() SSRF: --board Flag Reaches Metadata IPs

The `parseArgs()` function in boardcards.js accepted a user-controlled `--board` command-line argument and passed it directly to fetch() calls without validating the URL scheme or hostname. An attacker could supply `http://169.254.169.254/latest/meta-data/` or other internal addresses to extract cloud credentials or scan internal networks.

high

fetch() with Automatic Redirects Leaks HTTPS Trust to api.tomys.top

The `withProxy()` fetch wrapper allowed automatic HTTP redirects from `api.tomys.top`, trusting the external API's domain integrity without validating final destinations. A compromised or malicious redirect response could send users to attacker-controlled phishing sites while maintaining HTTPS protocol and hostname checks that falsely appear secure.

high

Meta.get() Honored @uploadURL From Script Headers: SSRF Fix

A userscript manager's metadata parser accepted the `@uploadURL` directive from a script's own header block, so any installed or auto-updated script could silently redirect the options-page `uploadScript()` fetch to an attacker-chosen destination — including loopback, link-local metadata endpoints, and LAN addresses. The fix makes `Meta.get()` ignore `@uploadURL` when it appears in a script header, leaving the User Metadata field (validated in `Meta.getUserMeta()`) as the only way to set it, and