CVEReports
CVEReports

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

Product

  • Home
  • 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-27738

Angular SSR: The One-Slash Wonder (CVE-2026-27738)

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 26, 2026·7 min read·63 visits

Executive Summary (TL;DR)

Angular SSR's URL normalization logic only stripped a single leading slash from path segments. Attackers sending a `X-Forwarded-Prefix: ///evil.com` header can trick the server into generating a `Location: //evil.com` redirect. This protocol-relative URL forces the browser to navigate to the attacker's domain, enabling high-credibility phishing attacks.

A deceptively simple logic error in Angular's Server-Side Rendering (SSR) engine allows attackers to turn internal redirects into open redirects. By exploiting how the framework normalizes URLs from the `X-Forwarded-Prefix` header, a malicious actor can bypass validation with extra slashes, leading to protocol-relative URL redirection. This flaw affects major versions 19, 20, and 21, turning trusted applications into phishing launchpads.

The Hook: Trusting the Proxy

Server-Side Rendering (SSR) is the magic glue that makes heavy JavaScript frameworks feel snappy and SEO-friendly. But SSR is also a dangerous bridge between the raw, untrusted internet and your internal application logic. In the modern cloud stack, your Angular app rarely sits naked on the internet. It lives behind layers of Nginx, AWS ALBs, or Cloudflare, all of which helpfully annotate requests with headers like X-Forwarded-For and X-Forwarded-Prefix so the app knows where it supposedly lives.

Here is the problem: Angular decided to trust these headers a little too much. Specifically, the @angular/ssr package needs to construct full URLs when performing redirects (like when you hit a protected route and get bounced to /login). To do this, it stitches together the base URL and the target path. It sounds simple. It sounds boring. But in the world of exploit development, "boring" utility functions are where the bodies are buried.

CVE-2026-27738 isn't a complex buffer overflow or a heap grooming masterpiece. It is a testament to the fact that developers still treat input validation like a chore rather than a survival skill. The vulnerability lies in a helper function designed to clean up URL paths. It tries to be helpful by removing leading slashes to avoid double-slashing. Spoiler alert: it didn't remove enough of them.

The Flaw: The 'If' That Should Have Been a 'While'

Let's talk about joinUrlParts. This utility function in packages/angular/ssr/src/utils/url.ts has one job: take a bunch of string segments and glue them together into a valid URL path. To prevent the classic //path//subpath mess, it attempts to normalize the segments by stripping leading slashes before joining them.

Here is where the developer's optimism collided with reality. The code checked if a segment started with a slash. If it did, it removed it. Singular. Once. It assumed that a path segment would only ever have one accidental leading slash. It looked something like this:

// The logic of a optimist
if (part[0] === '/') {
  normalizedPart = normalizedPart.slice(1);
}

See the issue? If I hand you /home, you give me home. Perfect. But what if I hand you ///evil.com? The code sees the first slash, says "Gotcha!", removes it, and leaves //evil.com. In the world of browsers, // isn't just two slashes; it's a protocol-relative URL. It tells the browser, "Keep using HTTPS, but switch the host to evil.com."

This is the digital equivalent of a bouncer checking your ID, seeing you have a fake mustache, peeling it off, but failing to notice the second, smaller fake mustache underneath.

The Code: Anatomy of a Fix

The fix provided by the Angular team is a textbook example of "defense in depth" replacing "naive trust." They didn't just fix the loop; they scorched the earth. Let's look at the critical diff in the joinUrlParts function.

The Vulnerable Code:

// Old logic: strictly checks index 0
if (part.startsWith('/')) {
  part = part.substring(1);
}

The Fix (Commit 877f017):

The new implementation treats slashes like an infestation. It uses a while loop to aggressively strip every leading and trailing slash it finds. It doesn't matter if you send ///, ////, or //////////////////—they are all getting nuked.

export function joinUrlParts(...parts: string[]): string {
  const normalizedParts: string[] = [];
  for (const part of parts) {
    let start = 0;
    let end = part.length;
    // Eat all the slashes at the start
    while (start < end && part[start] === '/') { start++; }
    // Eat all the slashes at the end
    while (end > start && part[end - 1] === '/') { end--; }
    
    if (start < end) {
      normalizedParts.push(part.slice(start, end));
    }
  }
  return addLeadingSlash(normalizedParts.join('/'));
}

But they didn't stop there. They realized that X-Forwarded-Prefix shouldn't contain suspicious characters at all. They added a regex validator INVALID_PREFIX_REGEX that instantly throws an error if the header contains double slashes or directory traversal sequences (..).

const INVALID_PREFIX_REGEX = /^[\/\\]{2}|(?:^|[\/\\])\.\.?(?:[\/\\]|$)/;

This is the difference between "patching a bug" and "killing a bug class."

The Exploit: Hijacking the Redirect

So, how do we weaponize this? We need an Angular SSR app sitting behind a proxy (like Nginx) that blindly passes the X-Forwarded-Prefix header. This is a very common configuration for apps hosted on sub-paths (e.g., example.com/app/).

The Setup:

  1. Target: https://vulnerable-bank.com
  2. Goal: Redirect users to https://evil-phishing.com
  3. Vector: The /logout route, which redirects users back to /home after clearing the session.

The Attack: We craft a link or use a CSRF chain to force a request with a manipulated header. If we can control the upstream proxy or if the application is misconfigured to trust client headers directly (common in dev/staging), we send this:

GET /logout HTTP/1.1
Host: vulnerable-bank.com
X-Forwarded-Prefix: ///evil-phishing.com

The Execution:

  1. Angular SSR receives the request.
  2. It needs to build the redirect URL for the home page.
  3. It calls joinUrlParts('///evil-phishing.com', 'home').
  4. The function strips one slash: //evil-phishing.com.
  5. It appends the path: //evil-phishing.com/home.
  6. The server responds:
HTTP/1.1 302 Found
Location: //evil-phishing.com/home

The Result: The victim's browser sees //evil-phishing.com/home. Since the original page was loaded over HTTPS, the browser expands this to https://evil-phishing.com/home. The user is silently whisked away to the attacker's domain, which likely looks exactly like the bank's login page.

The Impact: Why You Should Care

Security engineers often roll their eyes at Open Redirects. "So what? The user goes to the wrong page." But in the context of a trusted application, an Open Redirect is a silver bullet for social engineering.

First, there is the Phishing Implication. Users are trained to check the URL bar. If they click a link that starts with vulnerable-bank.com, they let their guard down. If that link immediately 302s them to a clone site, they rarely notice the switch. The initial trust is established by the valid domain.

Second, consider Cache Poisoning. If the X-Forwarded-Prefix header is not part of the cache key (the Vary header) on your CDN, an attacker could send a single malicious request that gets cached. Now, every legitimate user who visits that page gets redirected to the malware site. This turns a targeted attack into a Denial of Service or a mass-compromise event.

Finally, this bypasses many SSRF filters. While this specific CVE results in a client-side redirect, the underlying logic flaw—insufficient sanitization of path components—often mirrors how internal requests are constructed. If this logic was used to fetch internal resources, we'd be looking at a much nastier RCE scenario.

The Fix: Sanitization and Upgrades

If you are running Angular SSR on versions 19, 20, or 21, you are exposed. The immediate fix is to upgrade to the patched versions:

  • v21.x: Upgrade to 21.1.5
  • v20.x: Upgrade to 20.3.17
  • v19.x: Upgrade to 19.2.21

If you cannot upgrade immediately (corporate bureaucracy is the real vulnerability, after all), you must sanitize the input before it reaches Angular. In your server.ts or Nginx configuration, you need to flatten that header.

Nginx Mitigation: Ensure you are hardcoding the prefix if you know it, rather than trusting the client. If you must pass it dynamically, validate it.

# Don't do this if you can avoid it
# proxy_set_header X-Forwarded-Prefix $http_x_forwarded_prefix;
 
# Do this: explicitly define the prefix
proxy_set_header X-Forwarded-Prefix /my-app;

Node.js Middleware Mitigation:

// Add this early in your server stack
app.use((req, res, next) => {
  const prefix = req.headers['x-forwarded-prefix'];
  if (typeof prefix === 'string' && prefix.startsWith('//')) {
    // Flatten multiple slashes to one
    req.headers['x-forwarded-prefix'] = prefix.replace(/^\/+/, '/');
  }
  next();
});

This isn't just about fixing a bug; it's about acknowledging that "normalization" is hard and that headers are user input. Treat them accordingly.

Official Patches

AngularPatch Commit on GitHub
AngularGitHub Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
6.1/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N

Affected Systems

Angular SSR 19.x < 19.2.21Angular SSR 20.x < 20.3.17Angular SSR 21.x < 21.1.5

Affected Versions Detail

Product
Affected Versions
Fixed Version
@angular/ssr
Angular
>= 19.0.0-next.0, < 19.2.2119.2.21
@angular/ssr
Angular
>= 20.0.0-next.0, < 20.3.1720.3.17
@angular/ssr
Angular
>= 21.0.0-next.0, < 21.1.521.1.5
AttributeDetail
CWECWE-601 (Open Redirect)
CVSS v4.06.9 (Medium)
Attack VectorNetwork (Header Manipulation)
Exploit MaturityProof of Concept
PrivilegesNone
User InteractionRequired (Victim must click link)

MITRE ATT&CK Mapping

T1566.002Spearphishing Link
Initial Access
T1608.002Stage Capabilities: Upload Malware
Resource Development
CWE-601
Open Redirect

URL Redirection to Untrusted Site ('Open Redirect')

Known Exploits & Detection

GitHubOriginal issue report containing PoC steps

Vulnerability Timeline

Vulnerability reported to Google Bug Hunters
2026-02-15
Patch merged and released
2026-02-23
CVE and GHSA published
2026-02-25

References & Sources

  • [1]GHSA-xh43-g2fq-wjrj
  • [2]NVD CVE-2026-27738

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.

More Reports

•about 1 hour ago•CVE-2026-107715
6.8

CVE-2026-107715: Information Disclosure and Credential Leakage in Ruby Mechanize via Cross-Origin Redirections

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.

Alon Barad
Alon Barad
2 views•7 min read
•about 2 hours ago•CVE-2026-107399
6.8

CVE-2026-107399: Information Disclosure via HTML Meta-Refresh in Ruby Mechanize

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.

Amit Schendel
Amit Schendel
4 views•5 min read
•about 3 hours ago•CVE-2026-107718
6.1

CVE-2026-107718: Open Redirect Vulnerability in @adonisjs/http-server

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.

Alon Barad
Alon Barad
4 views•6 min read
•about 4 hours ago•CVE-2026-107725
8.7

CVE-2026-107725: Remote Code Execution via Authorization Bypass in Hazelcast Predicates API

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.

Amit Schendel
Amit Schendel
5 views•7 min read
•about 5 hours ago•CVE-2026-107396
5.4

CVE-2026-107396: Stored Cross-Site Scripting (XSS) in Indico

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.

Alon Barad
Alon Barad
4 views•6 min read
•about 6 hours ago•CVE-2026-107397
4.4

CVE-2026-107397: Stored Cross-Site Scripting via Collaborative Editor Conflict Resolution and Custom Link Fields in Indico

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.

Alon Barad
Alon Barad
0 views•7 min read