Feb 26, 2026·6 min read·100 visits
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.
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 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.
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.
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.
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.
trusted-maps.org/proxy/http://evil.com/login and might trust it more than a raw link.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.
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.
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| Product | Affected Versions | Fixed Version |
|---|---|---|
terriajs-server TerriaJS | < 4.0.3 | 4.0.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-20 |
| Attack Vector | Network |
| CVSS v4 | 8.7 (High) |
| EPSS Score | 0.00082 |
| Impact | SSRF / Open Proxy |
| Exploit Status | POC Available |
Improper Input Validation
Ruby Mechanize prior to version 2.14.1 contains an information disclosure vulnerability. When executing cross-origin HTTP redirects, global headers configured on the Mechanize agent (such as Authorization or Session Cookies) are dynamically re-applied to the subsequent request, bypassing the internal header-stripping logic. An attacker who controls a redirection endpoint can capture sensitive bearer tokens or cookies.
An origin trust boundary failure in the Ruby mechanize library (prior to v2.14.1) allows unauthenticated remote web servers to harvest sensitive global request headers, such as Authorization Bearer tokens and cookies, by utilizing HTML-level meta-refresh redirection tags. Standard HTTP-level redirect boundaries were not applied to document-level redirects, creating a vector for cross-origin credential leakage during automated crawls.
CVE-2026-107718 is a medium-severity Open Redirect vulnerability in the core HTTP server package of the AdonisJS Node.js framework. Prior to versions 8.2.3 and 9.3.0, the framework built route paths by directly interpolating dynamic parameters and wildcard segments without URI encoding. If an application routes attacker-controlled input directly to a dynamic first path segment and uses the generated route URL as a redirect destination, a leading slash can produce a scheme-relative external URL. Modern web browsers process scheme-relative URLs by redirecting the client to the specified external domain, exposing users to credential harvesting, social engineering, and session hijacking. This vulnerability affects all applications running unpatched configurations where input validation is not explicitly implemented before generating paths.
CVE-2026-107725 is a critical security bypass in Hazelcast where missing authorization checks in the MapPermission class permit unprivileged clients to issue queries containing aggregators or projections. This architectural oversight allows attackers to run arbitrary code on the cluster servers under the privileges of the active Hazelcast process.
A stored Cross-Site Scripting (XSS) vulnerability was identified in Indico, an open-source event management system developed at CERN, prior to version 3.3.13. The vulnerability stems from weak URL validation in custom link fields and lack of HTML sanitization during Marshmallow serialization of event notes. This allows authenticated attackers with event modification privileges to inject malicious payloads that execute in the browser of users viewing the event pages or collaborating on notes.
A technical analysis of CVE-2026-107397, a stored Cross-Site Scripting (XSS) vulnerability in Indico's collaborative notes editor and custom link generation fields. Prior to version 3.3.13, Marshmallow serialization schemas omitted HTML sanitization during conflict resolution, and form validators failed to enforce strict URI schemes, enabling authenticated low-privilege attackers to execute arbitrary JavaScript.