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
Published August 28, 2026Reviewed 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

ip-address 10.2.0 SSRF: Inconsistent Parsing Bypasses IP Checks

The `ip-address` npm package version 10.2.0 contains an inconsistent parsing vulnerability that allows attackers to bypass IP-based access controls. By representing IPv4 addresses in IPv4-mapped IPv6 notation, attackers can trick applications into allowing requests to blocked internal addresses. Upgrading to 10.3.1 resolves this through stricter address normalization.

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