Back to Blog
high SEVERITY8 min read

How Inconsistent IP Address Parsing Happens in JavaScript and How to Fix It

A high-severity vulnerability in the `ip-address` npm package (CVE-2026-69192) allowed attackers to craft IPv4 addresses with leading-zero octets that the library decoded as decimal while system resolvers decoded them as octal — creating a dangerous parsing discrepancy that could enable Server-Side Request Forgery (SSRF) and trust-boundary bypass. The fix upgrades `ip-address` from version 10.1.0 to 10.3.1 in the `core/http/react-ui` frontend dependency tree, eliminating the inconsistency and en

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

Answer Summary

CVE-2026-69192 is a high-severity SSRF vulnerability (CWE-918) in the `ip-address` npm package affecting versions before 10.3.1. The `Address4` class decoded IPv4 octets with leading zeros as decimal numbers, while OS-level and many network resolvers interpret them as octal — a classic parser differential that attackers exploit to bypass IP allowlists and reach internal services. The fix is to upgrade `ip-address` to version 10.3.1, which adds an explicit override entry in `bun.lock` and `package.json` to ensure the corrected version is resolved throughout the dependency tree.

Vulnerability at a Glance

cweCWE-918
fixUpgrade ip-address to 10.3.1 and add an explicit override in bun.lock
riskAttackers bypass IP allowlists to reach internal/loopback services
languageJavaScript / TypeScript (Node.js / Bun)
root causeAddress4 parsed leading-zero octets as decimal; resolvers parse them as octal
vulnerabilityServer-Side Request Forgery via inconsistent IP address parsing

How Inconsistent IP Address Parsing Happens in JavaScript and How to Fix It


At a Glance

Field Detail
CVE CVE-2026-69192
Package ip-address < 10.3.1
Severity High
CWE CWE-918 — Server-Side Request Forgery
Impact SSRF, trust-boundary bypass
Fix Upgrade to ip-address@10.3.1

Introduction

The core/http/react-ui frontend depends on @modelcontextprotocol/sdk, which in turn pulls in the ip-address npm package for IPv4/IPv6 address validation. On the surface, this looks like a routine utility dependency — but version 10.1.0 of ip-address contains a subtle, high-severity flaw in how its Address4 class handles octets with leading zeros.

When Address4 encounters an address like 010.0.0.1, it reads the leading-zero octet as decimal 10. But POSIX-compliant system resolvers — and many network stacks — interpret a leading zero as an octal prefix, making 010 equal to decimal 8. This one-digit difference is the entire attack surface.

If your application uses ip-address to validate or allowlist IPv4 addresses before passing them to an HTTP client or system resolver, an attacker can craft an address that passes your validation (because the library sees 10.0.0.1) but resolves differently at the network layer (because the OS sees 8.0.0.1 — or, more dangerously, routes to a private/loopback address entirely).


The Vulnerability Explained

The Octal Trap in IPv4 Notation

In C and many Unix-derived systems, numeric literals with a leading zero are octal. This convention leaked into early socket APIs and remains in POSIX inet_aton(). Consider these two interpretations of the same string:

Address string:  010.0.0.1

ip-address 10.1.0 (Address4):  10.0.0.1    decimal interpretation
POSIX inet_aton / many resolvers:   8.0.0.1    octal interpretation

Now imagine an attacker wants to reach 127.0.0.1 (loopback) on a server that blocks 127.x.x.x in its allowlist. They can try:

0177.0.0.1
  • ip-address 10.1.0 sees: 177.0.0.1not loopback, passes the allowlist check ✅
  • System resolver sees: 0177 = octal 127 → 127.0.0.1is loopback, connects to internal service ✅

The validation says "safe." The network says "internal." That gap is SSRF.

Where This Lives in the Dependency Tree

The vulnerable package entered the project through core/http/react-ui/bun.lock. Before the fix, the lock file resolved ip-address to version 10.1.0 as a transitive dependency of @modelcontextprotocol/sdk@1.27.1:

# bun.lock (before fix) — relevant excerpt
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", {
  "dependencies": {
    "@hono/node-server": "^1.19.9",
    ...
    "hono": "^4.11.4",
    ...
  }
}]

The ip-address package was not pinned with an override, so Bun resolved whatever version satisfied the semver range — which landed on the vulnerable 10.1.0.

Attack Scenario

Here's a concrete exploitation path for this application:

  1. The React UI communicates with a backend Go service (noted in the PR threat model as "a Go service — vulnerabilities in HTTP handlers are remotely exploitable").
  2. The frontend or its BFF (Backend for Frontend) uses @modelcontextprotocol/sdk to validate or route MCP (Model Context Protocol) endpoint URLs.
  3. An attacker supplies a crafted IP in a tool/resource URL: http://0177.0.0.1:8080/admin
  4. Address4 from ip-address 10.1.0 parses 0177 as decimal 177177.0.0.1 — not in the private range blocklist.
  5. The SDK forwards the request. The OS resolver interprets 0177 as octal → connects to 127.0.0.1:8080/admin — the local admin interface.
  6. The attacker has achieved SSRF to a loopback service that was never meant to be externally reachable.

The Fix

What Changed

The fix makes two targeted edits to enforce ip-address@10.3.1 across the entire dependency tree:

1. core/http/react-ui/bun.lock — Added an explicit override

  "overrides": {
-   "hono": "4.12.25",
+   "hono": "4.12.34",
+   "ip-address": "10.3.1",
  },

The overrides field in Bun's lock file forces every package in the tree that depends on ip-address to resolve to exactly 10.3.1, regardless of what semver range they declare. Without this override, a transitive dependency could silently re-introduce the vulnerable version.

2. core/http/react-ui/package.json — Updated @modelcontextprotocol/sdk range

- "@modelcontextprotocol/sdk": "^1.25.1",
+ "@modelcontextprotocol/sdk": "^1.30.0",

Bumping to ^1.30.0 also picks up the SDK's own internal dependency updates, reducing the chance that the SDK itself re-pins to an older ip-address.

Why the Override Is the Critical Part

Simply upgrading the SDK might not be enough. If any other package in the tree declares "ip-address": "^10.0.0", Bun could still resolve 10.1.0 for that package. The "ip-address": "10.3.1" override entry acts as a fleet-wide pin — it is the authoritative, non-negotiable version for every consumer in this project.

What Version 10.3.1 Actually Fixes

ip-address 10.3.1 updates the Address4 parser to detect leading-zero octets and either:
- Reject them as invalid (strict mode), or
- Normalize them by stripping the leading zero before numeric conversion

Either behavior eliminates the decimal/octal discrepancy, ensuring that whatever IP string passes Address4 validation is also what the downstream resolver will connect to.


Key Takeaways

  • Leading-zero octets are a parsing landmine: 0177.0.0.1 is 177.0.0.1 to Address4 in ip-address < 10.3.1 but 127.0.0.1 (loopback) to the OS resolver — a gap wide enough to drive SSRF through.
  • Transitive dependencies need explicit overrides: The vulnerable ip-address version entered through @modelcontextprotocol/sdk, not a direct dependency. The "ip-address": "10.3.1" override in bun.lock is what actually enforces the safe version fleet-wide.
  • Upgrading the direct dependency alone is not always enough: Bumping @modelcontextprotocol/sdk to ^1.30.0 helps, but without the overrides entry, other packages could still resolve the old version.
  • SSRF in MCP/BFF layers is high-impact: The Model Context Protocol SDK routes to external tool endpoints — if an attacker can influence those URLs, SSRF gives them access to any service reachable from the server's network, including internal admin APIs.
  • SCA tooling catches what code review misses: No human reviewer scanning a bun.lock diff would spot a vulnerable transitive dependency version; automated scanners like Trivy are essential for this class of issue.

How Orbis AppSec Detected This

  • Source: User-influenced IP address strings passed to Address4 via @modelcontextprotocol/sdk URL routing logic
  • Sink: Address4 constructor in ip-address@10.1.0 — the point where the octal/decimal discrepancy manifests before the address is forwarded to a network resolver
  • Missing control: No version override for ip-address in bun.lock, allowing the vulnerable 10.1.0 to be resolved as a transitive dependency; no normalization of leading-zero octets before network calls
  • CWE: CWE-918 — Server-Side Request Forgery (SSRF)
  • Fix: Added "ip-address": "10.3.1" to the overrides block in bun.lock and upgraded @modelcontextprotocol/sdk to ^1.30.0 in package.json, forcing the safe parser version across the entire 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 is a reminder that security vulnerabilities don't always look like buffer overflows or SQL injections — sometimes they hide in the gap between two components that both think they're parsing the same string correctly. The ip-address library's Address4 class and the system resolver were each internally consistent; the danger lived in their disagreement about what a leading zero means.

The fix is surgical: a two-line change to bun.lock and package.json that pins ip-address to 10.3.1 and ensures no future dependency resolution can silently downgrade it. But the broader lesson is about defense in depth — IP allowlist validation is only as strong as the parser implementing it, and parsers need to be held to the same standard as any other security control: pinned, tested, and monitored for CVEs.

For any application that routes requests based on user-supplied IP addresses or URLs — especially those integrating with protocol SDKs like MCP — this class of parser-differential vulnerability deserves explicit attention in your threat model.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #11632

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