CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27818
8.70.08%

Close But No Cigar: The TerriaJS SSRF Suffix Bypass

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 26, 2026·6 min read·4 visits

PoC Available

Executive Summary (TL;DR)

TerriaJS-Server versions prior to 4.0.3 used a flawed logic check to validate proxy targets. It checked if a requested host *ended with* a trusted domain string without ensuring a dot separator. This allowed attackers to register domains like `evil-trusted.com` to bypass the whitelist for `trusted.com`. Fix requires updating to 4.0.3 where strict subdomain validation is enforced.

A classic string validation error in the TerriaJS-Server proxy controller allowed attackers to bypass domain allowlists. By relying on a primitive `indexOf` check to validate hostnames, the server failed to distinguish between legitimate subdomains and malicious domains sharing a common suffix. This vulnerability transforms the geospatial data server into an open proxy, enabling Server-Side Request Forgery (SSRF) and potential network scanning.

The Hook: Proxies are Hard

If you have ever built a modern web application that mashes up data from different sources, you know the pain of Cross-Origin Resource Sharing (CORS). Browsers are paranoid, and rightfully so. To get around this, developers often deploy a "proxy"—a server-side component that fetches data on behalf of the client, stripping away those pesky CORS headers and handing the data back to the browser like a polite waiter.

TerriaJS, a robust library for building geospatial data explorers, includes terriajs-server specifically for this purpose. It allows the frontend to request map tiles and heavy JSON payloads from third-party servers. But obviously, you can't just run an open proxy on the internet. That's how you get your server blacklisted by every ISP on the planet. So, TerriaJS implements a proxyableDomains allowlist. It's the bouncer at the club, checking IDs to make sure only VIPs (trusted domains) get in.

Unfortunately, in CVE-2026-27818, the bouncer was a bit too lax. He wasn't checking the ID; he was just checking if your name sounded vaguely similar to someone on the list. This isn't just a configuration error; it's a fundamental misunderstanding of how string matching works in a security context.

The Flaw: The Dangling Suffix

The vulnerability lies deep within lib/controllers/proxy.js. The goal was simple: ensure the requested host is present in the proxyableDomains array. A naive developer might iterate through the list and check if the host contains the trusted domain. A slightly smarter developer would check if the host ends with the trusted domain to allow subdomains (e.g., allowing google.com should also allow maps.google.com).

The TerriaJS implementation did exactly that, but with a fatal flaw. It used indexOf with a calculated offset to verify the ending. Here is the logic in plain English: "If the trusted string is found exactly at the end of the requested string, let it in."

The problem? DNS relies on dots (.) to separate hierarchy. This code ignored that. If your allowed domain is example.com, the code effectively says "anything ending in example.com is fine." This means attacker-example.com, not-example.com, and evilexample.com are all treated as valid subdomains of example.com. They are not. They are entirely different domains that just happen to share a suffix.

The Code: String Math vs. Security

Let's look at the smoking gun. This is the code that ran in production servers prior to version 4.0.3. It’s a perfect example of why you shouldn't do "string math" for security boundaries.

The Vulnerable Code:

// host is the attacker-controlled input
// proxyDomains[i] is the trusted whitelist item
 
if (
  host.indexOf(proxyDomains[i], host.length - proxyDomains[i].length) !== -1
) {
    // Access Granted!
}

See the issue? If host is evilcorp.com and proxyDomains[i] is corp.com, the math works out perfectly. evilcorp.com ends with corp.com. The check passes, and the server fetches content from the attacker's domain.

The Fix (Commit 3aaa5d9): The patch introduces the necessary boundary check. It forces the match to be either identical OR strictly a subdomain preceded by a dot.

const domainLower = proxyDomains[i].toLowerCase();
if (
  host === domainLower || host.endsWith("." + domainLower)
) {
    // Access Granted, safely.
}

By adding the dot (.) to the check (e.g., looking for .example.com), they eliminated the suffix collision class of attacks entirely. It’s a one-character difference that separates a secure proxy from an open relay.

The Exploit: Bypassing the Bouncer

Exploiting this is trivially easy and requires no special tooling—just a domain registrar and a web browser. Let's assume the victim server has whitelisted data.gov because it's a mapping application.

Step 1: Reconnaissance First, we verify the target is running TerriaJS-Server. We can usually identify this by the /proxy/ endpoint structure. We then guess the whitelist. Common mapping applications almost always whitelist arcgis.com, google.com, or data.gov.

Step 2: The Setup We purchase a domain that creates a suffix collision. Let's buy my-malicious-data.gov? No, we can't buy .gov domains. But if the whitelist has mapbox.com, we can buy evilmapbox.com. Let's assume the whitelist contains generic-mapping-provider.com.

We register attacker-generic-mapping-provider.com. We point this domain to our own C2 server running a listener.

Step 3: The Attack We send the following request to the victim: GET /proxy/http://attacker-generic-mapping-provider.com/shell.php

The server checks: Does attacker-generic-mapping-provider.com end with generic-mapping-provider.com? Yes. The request is proxied. The victim server connects to us. We can now serve malicious content that appears to come from the trusted TerriaJS server, or simply use their bandwidth to hide our identity.

The Impact: More Than Just a Proxy

Why is this CVSS 8.7? Isn't it just an open proxy? Not quite. In the context of enterprise mapping applications, these servers often sit inside a perimeter. While this specific exploit relies on external DNS resolution (you need to own the domain), the implications of SSRF are broad.

  1. Reputation Laundering: Attackers can use your server to host phishing pages. Users see a link to trusted-maps.org/proxy/http://evil.com/login and might trust it more than a raw link.
  2. IP Masking: The attacker hides behind your server's IP address to conduct attacks on other targets, effectively making you an accomplice.
  3. Internal Access (Edge Case): If the whitelist contains internal domain names (e.g., internal.corp), and the attacker can find a way to resolve a suffix-matching domain to an internal IP (via DNS rebinding or Split DNS configurations), they could map the internal network.

Most critically, this allows an attacker to bypass the intended access controls of the application completely. The proxyableDomains config is the only thing stopping this server from being a free VPN for the internet. Breaking it breaks the security model of the application.

Mitigation: Patching and Lessons Learned

The immediate fix is to upgrade terriajs-server to version 4.0.3. This version implements the correct boundary checks for subdomains.

If upgrading is impossible (it never is, but let's pretend), you can monkey-patch the lib/controllers/proxy.js file manually. Replace the indexOf check with a strict .endsWith('.' + domain) check. Additionally, verify your proxyableDomains config. If you have extremely short domains listed (like .com or co.uk), remove them immediately. Whitelisting TLDs is suicide.

For Developers: Never use indexOf, includes, or regex without anchors (^ and $) for validating security boundaries. URLs are structured data. Use the URL parser (new URL()) to extract the hostname, and then validate the hostname segments individually. String manipulation is the enemy of security.

Official Patches

TerriaJSGitHub Commit fixing the issue

Fix Analysis (1)

Technical Appendix

CVSS Score
8.7/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
EPSS Probability
0.08%
Top 100% most exploited

Affected Systems

TerriaJS-Server < 4.0.3NodeJS Express applications using TerriaJS proxy middleware

Affected Versions Detail

Product
Affected Versions
Fixed Version
terriajs-server
TerriaJS
< 4.0.34.0.3
AttributeDetail
CWE IDCWE-20
Attack VectorNetwork
CVSS v48.7 (High)
EPSS Score0.00082
ImpactSSRF / Open Proxy
Exploit StatusPOC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1566Phishing
Initial Access
CWE-20
Improper Input Validation

Improper Input Validation

Known Exploits & Detection

N/AExploit methodology described in security advisory

Vulnerability Timeline

Fix commit merged
2025-12-02
CVE Published
2026-02-26

References & Sources

  • [1]GitHub Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.