The Hidden Danger in IP Address Parsing
In the devboard server component, we discovered a high-severity SSRF vulnerability in devboard/server/package-lock.json affecting the ip-address npm package. This wasn't a typical SSRF where validation was missing—it was far more subtle. The application was validating IP addresses, but the validation library and the DNS resolver were speaking different languages when it came to leading-zero octets.
The ip-address package version 10.2.0 decoded an address like 0127.0.0.1 as decimal, treating the leading zero as insignificant. It would parse this as 127.0.0.1 (localhost). However, when the actual HTTP request was made, the system's DNS resolver or network stack interpreted 0127 as octal (base-8), converting it to decimal 87. The result? The application thought it was blocking requests to localhost, but attackers could bypass the check and reach 87.0.0.1 instead—potentially an internal service on the network.
This parsing inconsistency created a trust-boundary bypass that could allow attackers to probe internal networks, access cloud metadata services, or interact with services that should be unreachable from external input.
The Vulnerability Explained
The vulnerability exists in how the Address4 class of the ip-address library (version 10.2.0 and earlier) handles IP address strings with leading zeros in octets. Let's examine the specific problem:
// Vulnerable code behavior in ip-address 10.2.0
const Address4 = require('ip-address').Address4;
// Application validates user input
const userInput = '0127.0.0.1';
const addr = new Address4(userInput);
// ip-address 10.2.0 interprets this as decimal
console.log(addr.address); // "127.0.0.1" - decimal interpretation
// But when this address is used in an HTTP request...
fetch(`http://${userInput}/api/data`)
// The system resolver interprets 0127 as OCTAL
// 0127 (octal) = 87 (decimal)
// Actual request goes to 87.0.0.1, not 127.0.0.1!
The attack scenario is straightforward but devastating:
- Setup: The devboard server has an allowlist blocking requests to internal IP ranges, including
127.0.0.0/8(localhost) - Validation: Application uses ip-address 10.2.0 to parse user-supplied target URLs
- Bypass: Attacker provides
http://0177.0.0.1/adminas a webhook URL - Validation passes: ip-address interprets this as
127.0.0.1(decimal), which is correctly blocked - Execution differs: The actual HTTP client's resolver interprets
0177as octal =127decimal, accessing localhost - Result: Attacker accesses internal admin panel that should be unreachable
An even more dangerous variant:
// Attacker targets AWS metadata service (169.254.169.254)
const malicious = '0251.0254.0251.0254';
// ip-address 10.2.0 sees: 251.254.251.254 (decimal) - NOT in AWS range
// Validation: PASS ✓
// System resolver sees: 169.254.169.254 (octal conversion) - AWS metadata!
// Actual request: SSRF to cloud credentials ✗
This specific vulnerability in the devboard server's dependency tree meant that any component using ip-address for validation before making HTTP requests was vulnerable to this bypass technique.
The Fix
The fix was implemented by upgrading the ip-address package from version 10.2.0 to 10.3.1 in the devboard server dependencies. Here's what changed:
Before (vulnerable - ip-address 10.2.0):
"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 (fixed - ip-address 10.3.1):
"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=="
}
The fix also added a package override in devboard/server/package.json to ensure the correct version is enforced across the entire dependency tree:
"overrides": {
"ip-address": "10.3.1"
}
This override is crucial because ip-address might be a transitive dependency (pulled in by other packages), and the override ensures that even indirect dependencies use the patched version.
How the fix works:
Version 10.3.1 of ip-address changes the parsing behavior to align with how DNS resolvers and network stacks interpret IP addresses. Specifically:
- Consistent octal handling: Leading-zero octets are now treated as octal, matching system resolver behavior
- Normalization: IP addresses are canonicalized to their true numeric values before validation
- Rejection option: The library can now reject ambiguous formats entirely in strict mode
The security improvement is concrete: after this upgrade, when the application validates 0127.0.0.1, the ip-address library now interprets it the same way the HTTP client will—as octal, converting to 87.0.0.1. If 87.0.0.1 is on the blocklist, the validation correctly rejects it. The trust boundary is restored.
Both files were modified because:
- package.json adds the override to enforce the version policy
- package-lock.json records the exact resolved version and integrity hash for reproducible builds
Prevention & Best Practices
To avoid IP address parsing vulnerabilities in your Node.js applications:
1. Use Canonical Forms for Validation
Always normalize IP addresses to their canonical form before comparing against allowlists or blocklists:
const Address4 = require('ip-address').Address4;
function isAllowed(ipString) {
try {
const addr = new Address4(ipString);
const canonical = addr.canonicalForm(); // e.g., "127.0.0.1"
// Now validate against canonical form
return !isPrivateIP(canonical);
} catch (e) {
// Invalid IP - reject
return false;
}
}
2. Validate After Parsing, Not Before
Don't validate the string representation—validate the parsed numeric value:
// BAD: String comparison
if (ipString.startsWith('127.')) { /* block */ }
// GOOD: Numeric comparison after parsing
const addr = new Address4(ipString);
if (addr.parsedAddress[0] === 127) { /* block */ }
3. Keep IP Parsing Libraries Updated
IP address parsing is deceptively complex. Libraries like ip-address handle edge cases including:
- Leading zeros (octal ambiguity)
- IPv4-mapped IPv6 addresses
- Hexadecimal notation
- Integer notation (e.g., 2130706433 = 127.0.0.1)
Use dependency scanning tools like Trivy, Snyk, or npm audit to catch vulnerable versions.
4. Implement Defense in Depth
Don't rely solely on IP validation:
- Use network segmentation to isolate internal services
- Implement application-level authentication for all services
- Monitor for unusual outbound connection patterns
- Use DNS rebinding protection (check IP at connection time, not just resolution time)
5. Test with Ambiguous Formats
Include test cases with tricky IP formats:
const testCases = [
'0127.0.0.1', // Octal
'0x7f.0.0.1', // Hexadecimal
'2130706433', // Integer notation
'127.0.0.0x1', // Mixed formats
'127.1', // Abbreviated
];
6. Reference Security Standards
- CWE-918: Server-Side Request Forgery (SSRF) - understand the attack class
- CWE-436: Interpretation Conflict - recognize parsing inconsistencies as a root cause
- OWASP SSRF Prevention Cheat Sheet: comprehensive guidance on preventing SSRF attacks
Key Takeaways
- The ip-address 10.2.0 library decoded leading-zero octets as decimal while DNS resolvers used octal, creating a parsing gap exploitable for SSRF attacks in the devboard server component
- String-based IP validation is insufficient—always parse to canonical form before comparing against allowlists to prevent format-based bypasses like
0127.0.0.1 - Package overrides in package.json are essential when fixing transitive dependencies, ensuring that ip-address 10.3.1 is used even when pulled in indirectly by other packages
- Ambiguous IP formats (octal, hex, integer notation) are attack vectors—use libraries that normalize these to canonical forms or reject them in strict mode
- CVE-2026-69192 demonstrates that even well-intentioned validation can fail when the validator and executor interpret data differently, highlighting the importance of semantic consistency across security boundaries
How Orbis AppSec Detected This
- Source: User-influenced input in webhook URLs, API target addresses, or other fields where the devboard server accepts IP addresses for outbound connections
- Sink: HTTP request functions (fetch, axios, http.request) that resolve and connect to the user-supplied IP address after validation by ip-address 10.2.0
- Missing control: Consistent parsing between the validation layer (ip-address library) and the execution layer (system DNS resolver), allowing octal-format addresses to bypass decimal-based allowlist checks
- CWE: CWE-918 (Server-Side Request Forgery) with contributing CWE-436 (Interpretation Conflict)
- Fix: Upgraded ip-address from 10.2.0 to 10.3.1, which aligns octal handling with system resolver behavior, and added package override to enforce the version across the dependency tree
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 in the ip-address npm package demonstrates how subtle parsing inconsistencies can create serious security vulnerabilities. The devboard server's upgrade from ip-address 10.2.0 to 10.3.1 closes a trust-boundary bypass that could have allowed attackers to access internal services through SSRF attacks exploiting octal notation.
This vulnerability reinforces a critical principle: security validation must use the same interpretation rules as the enforcement mechanism. When your allowlist validator sees "127.0.0.1" but your HTTP client connects to "87.0.0.1", you don't have security—you have a false sense of security.
By keeping dependencies updated, validating parsed canonical forms rather than string representations, and testing with ambiguous input formats, you can prevent similar vulnerabilities in your own applications. The automated detection and fix by Orbis AppSec shows how modern security tooling can catch these issues before they reach production.