Back to Blog
critical SEVERITY7 min read

How CORS Misconfiguration happens in Node.js with Hono and how to fix it

CVE-2026-54290 is a HIGH severity CORS misconfiguration in the Hono web framework where the CORS middleware incorrectly reflects any `Origin` header back to the client — including credentials — when the `origin` option defaults to a wildcard. Upgrading `hono` from `4.12.16` to `4.12.34` in `package-lock.json` and pinning the version via `overrides` in `package.json` closes the vulnerability. Left unpatched, this flaw could allow malicious cross-origin sites to make credentialed requests and read

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

Answer Summary

CVE-2026-54290 is a CORS Origin-reflection vulnerability (CWE-942) in the Hono Node.js web framework. When the `origin` option is left at its wildcard default, Hono's CORS middleware echoes back whatever `Origin` header the browser sends — even alongside `Access-Control-Allow-Credentials: true` — violating the Same-Origin Policy and enabling cross-site credential theft. The fix is to upgrade `hono` to version `4.12.34` (or later) and pin it via the `overrides` field in `package.json` so no transitive dependency can re-introduce the older, vulnerable version.

Vulnerability at a Glance

cweCWE-942 (Permissive Cross-domain Policy with Untrusted Domains)
fixUpgrade `hono` from `4.12.16` to `4.12.34` and pin the version in `package.json` overrides
riskMalicious sites can make credentialed cross-origin requests and read authenticated API responses
languageJavaScript / Node.js
root causeHono CORS middleware reflects any attacker-supplied `Origin` header instead of validating it against an allowlist
vulnerabilityCORS Origin Reflection with Credentials

The Webhook Server's Hidden CORS Problem

The src/webhook-server.mjs file sits at the edge of the application — it is the first thing the internet touches. It accepts incoming webhook payloads, routes them, and hands them off to internal plugin handlers. Because it is built on Hono, a lightweight Node.js web framework, it also inherits Hono's CORS middleware to manage cross-origin browser requests.

That inheritance came with a silent defect: CVE-2026-54290, a HIGH severity vulnerability in which Hono's CORS middleware reflects any Origin header supplied by the caller — including when credentials are involved — instead of validating it against a trusted list. Trivy's dependency scanner flagged hono@4.12.16 in package-lock.json as the carrier. The fix, merged via the PR fix: upgrade hono to 4.12.25 (CVE-2026-54290), upgrades the package to 4.12.34 and pins it so no transitive dependency can silently downgrade it.


The Vulnerability Explained

What CORS Is Supposed to Do

Cross-Origin Resource Sharing (CORS) is the browser mechanism that decides whether JavaScript running on https://evil.com is allowed to read a response from https://api.yourapp.com. The server signals its intent through response headers like:

Access-Control-Allow-Origin: https://trusted-partner.com
Access-Control-Allow-Credentials: true

When Access-Control-Allow-Origin names a specific origin and Access-Control-Allow-Credentials is true, the browser permits the cross-origin request and exposes the response body to the calling script — including cookies, auth tokens, and session data.

What Hono 4.12.16 Did Wrong

When the origin option in Hono's cors() middleware is left at its wildcard default, the vulnerable versions (up to and including 4.12.16) did not respond with a static *. Instead, they reflected the incoming Origin header verbatim back in Access-Control-Allow-Origin. The effective behavior looked like this:

-- Incoming request --
GET /webhooks/payload HTTP/1.1
Origin: https://evil.com
Cookie: session=abc123

-- Hono 4.12.16 response (vulnerable) --
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.com   ← reflected!
Access-Control-Allow-Credentials: true
Vary: Origin

The browser sees a specific origin match (not a wildcard) paired with credentials: true, so it considers the request legitimate and hands the full response body — including any session-scoped data — to the script on https://evil.com.

Why This Is Worse Than a Plain Wildcard

A plain Access-Control-Allow-Origin: * is bad, but browsers refuse to combine it with Access-Control-Allow-Credentials: true — that combination is explicitly forbidden by the CORS specification. Origin reflection sidesteps that browser protection entirely: because the value is a specific origin string (not *), the browser applies no such restriction, and credentialed cross-origin reads succeed.

Attack Scenario Against This Webhook Server

  1. An attacker registers https://evil-webhooks.io and hosts a page with:
fetch("https://api.yourapp.com/webhooks/payload", {
  credentials: "include",   // sends the victim's session cookie
  method: "GET"
})
.then(r => r.json())
.then(data => exfiltrate(data));  // sends payload to attacker's server
  1. The victim visits https://evil-webhooks.io while logged into yourapp.com.
  2. Hono 4.12.16 receives the request, sees Origin: https://evil-webhooks.io, and reflects it back.
  3. The browser allows the read. The attacker now has the webhook payload, which may contain API keys, internal event data, or PII.

The Fix

What Changed in package-lock.json

The core change replaces the vulnerable resolved tarball with the patched one:

 "node_modules/hono": {
-  "version": "4.12.16",
-  "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.16.tgz",
-  "integrity": "sha512-jN0ZewiNAWSe5khM3EyCmBb250+b40wWbwNILNfEvq84VREWwOIkuUsFONk/3i3nqkz7Oe1PcpM2mwQEK2L9Kg==",
+  "version": "4.12.34",
+  "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.34.tgz",
+  "integrity": "sha512-GqXJqY/xJkJmuloTrnV1ZEXG3fqte+VjkUqoRNZXcrUidiUOP4fMSIHHY4tsqZBK++kVyWmt/AAfSUuy57/eSA==",

4.12.34 contains the upstream patch that makes the CORS middleware validate the Origin header against the configured allowlist rather than reflecting it blindly.

What Changed in package.json

An overrides entry was added to lock hono to the patched version across the entire dependency tree:

 "overrides": {
-  "fast-uri": "4.1.2"
+  "fast-uri": "4.1.2",
+  "hono": "4.12.34"
 }

This is a critical companion change. Without the override, a transitive dependency that lists hono as a peer or direct dependency could cause npm to resolve a different (potentially older, vulnerable) version. The override acts as a version floor, ensuring 4.12.34 is used regardless of what any other package requests.

Before vs. After Behavior

Scenario Hono 4.12.16 (before) Hono 4.12.34 (after)
origin option not configured Reflects any Origin Returns * (no credentials)
origin: '*' with credentials Reflects any Origin + credentials Rejects the combination per spec
origin: ['https://trusted.com'] Works correctly Works correctly
Attacker-supplied Origin Reflected, credentials allowed Not reflected, request blocked

Prevention & Best Practices

1. Always Explicitly Configure origin in CORS Middleware

Never rely on defaults for security-sensitive middleware options. In Hono (and Express, Fastify, or any other framework), specify an explicit allowlist:

// ✅ Correct: explicit allowlist
app.use('/webhooks/*', cors({
  origin: ['https://dashboard.yourapp.com', 'https://partner.example.com'],
  credentials: true,
}));

// ❌ Dangerous: wildcard default with credentials
app.use('/webhooks/*', cors({
  credentials: true,
  // origin not set — vulnerable to reflection in older Hono
}));

2. Pin Security-Critical Dependencies with overrides

npm's overrides field (and Yarn's resolutions) lets you enforce a minimum safe version across your entire dependency tree. Use it for any package that touches request/response handling:

"overrides": {
  "hono": ">=4.12.34"
}

3. Run a Dependency Vulnerability Scanner in CI

Trivy detected CVE-2026-54290 automatically. Add it (or a similar tool) to your CI pipeline so vulnerable dependencies are caught before they merge:

# .github/workflows/security.yml
- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    scan-type: 'fs'
    scan-ref: '.'
    severity: 'HIGH,CRITICAL'
    exit-code: '1'

4. Understand the CORS Specification Nuances

The CORS specification explicitly forbids Access-Control-Allow-Origin: * combined with Access-Control-Allow-Credentials: true. However, it does not forbid a reflected specific origin combined with credentials — that loophole is what this CVE exploits. Knowing this distinction helps you audit CORS configurations more effectively.

5. Relevant Security Standards

  • CWE-942: Permissive Cross-domain Policy with Untrusted Domains
  • OWASP A05:2021 – Security Misconfiguration (overly permissive CORS is a canonical example)
  • OWASP CORS Cheat Sheet: recommends explicit origin allowlists and warns against reflection patterns

Key Takeaways

  • hono@4.12.16's default CORS behavior was exploitable: The origin wildcard default caused the middleware in src/webhook-server.mjs to reflect any attacker-supplied Origin header, bypassing the browser's credential-with-wildcard protection.
  • Origin reflection is more dangerous than a plain wildcard: Because it produces a specific-origin response, browsers apply no credential restriction — making session hijacking via cross-origin reads trivially achievable.
  • The overrides entry in package.json is as important as the package-lock.json change: Without it, transitive dependencies could silently re-introduce 4.12.16.
  • Trivy caught this before it was exploited: Automated dependency scanning in the CI pipeline is what surfaced CVE-2026-54290 — not a manual code review or a production incident.
  • Never leave CORS origin unconfigured in a production webhook server: Any endpoint that processes credentialed browser requests must enumerate its trusted origins explicitly.

How Orbis AppSec Detected This

  • Source: The Origin HTTP request header supplied by an untrusted browser or HTTP client
  • Sink: Hono's internal CORS middleware response-header writer in node_modules/hono (version 4.12.16), which copies the Origin value directly into Access-Control-Allow-Origin without allowlist validation — affecting every route in src/webhook-server.mjs that uses the cors() middleware
  • Missing control: No explicit origin allowlist was configured; the middleware defaulted to reflection mode instead of rejecting or wildcarding unknown origins
  • CWE: CWE-942 — Permissive Cross-domain Policy with Untrusted Domains
  • Fix: hono was upgraded from 4.12.16 to 4.12.34 in package-lock.json and pinned via the overrides field in package.json to prevent transitive re-introduction of the vulnerable version

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-54290 is a reminder that security vulnerabilities do not always live in the code you write — they live in the code you depend on. Hono's CORS middleware, left at its default configuration, silently transformed src/webhook-server.mjs into a credentialed cross-origin read target. The fix was two files and three lines: a version bump in package-lock.json and a version pin in package.json. The lesson is broader: treat CORS configuration as a security control, not a convenience setting; pin your dependencies; and let automated scanners do the work of watching your dependency tree so you can focus on building.


References

Frequently Asked Questions

What is CORS Origin reflection?

CORS Origin reflection occurs when a server copies the incoming `Origin` request header directly into the `Access-Control-Allow-Origin` response header without checking it against a trusted allowlist, effectively granting every origin the same trust as an explicitly permitted one.

How do you prevent CORS Origin reflection in Node.js?

Always configure your CORS middleware with an explicit allowlist of trusted origins. Never rely on wildcard defaults when `credentials: true` is also set, and pin your framework dependencies to versions that enforce this rule.

What CWE is CORS Origin reflection?

CORS Origin reflection maps to CWE-942: Permissive Cross-domain Policy with Untrusted Domains, which describes overly broad cross-origin access controls that expose sensitive resources to untrusted parties.

Is setting `credentials: false` enough to prevent CORS Origin reflection?

Disabling credentials mitigates the most severe impact (session hijacking), but it does not fix the underlying misconfiguration. An attacker could still read unauthenticated API responses that contain sensitive data. The correct fix is to validate the `Origin` header against a strict allowlist.

Can static analysis detect CORS Origin reflection?

Yes. Tools like Trivy (which flagged this exact issue as CVE-2026-54290) and Semgrep rules targeting CORS middleware configurations can identify dangerous wildcard or reflection patterns in dependency trees and application code before they reach production.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #75

Related Articles

high

How Denial of Service via Infinite Loop happens in Node.js and how to fix it

A critical Denial of Service vulnerability (CVE-2026-67213) in the nanoid package allowed attackers to trigger infinite loops during random ID generation. This fix upgrades nanoid from version 3.3.11 to 3.3.18 using npm overrides, eliminating the infinite loop condition in the customAlphabet function that could crash Node.js applications.

high

How package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age happens in pnpm workspaces and how to fix it

A pnpm workspace configuration was missing the `minimumReleaseAge` setting, allowing freshly published (and potentially malicious) package versions to be installed immediately. The fix adds a 7-day quarantine period along with `blockExoticSubdeps` and `trustPolicy: no-downgrade` to harden the supply chain against package takeover attacks.

critical

How WebSocket Protocol Handler Vulnerabilities happen in Node.js Dependencies and how to fix it

A critical vulnerability (CVE-2026-54466) was discovered in websocket-driver version 0.7.4, a WebSocket protocol handler used in the dependency tree. The vulnerability allowed attackers to exploit flaws in WebSocket frame parsing, potentially leading to denial of service or protocol-level attacks. The fix upgraded websocket-driver to version 0.7.5, which patches the protocol handling vulnerabilities and hardens input validation for untrusted WebSocket frames.

high

How Silent Form Limit Bypasses Happen in Starlette and How to Fix Them

CVE-2026-54283 is a high-severity Denial of Service vulnerability in Starlette where form size limits set on `request.form()` were silently ignored for `application/x-www-form-urlencoded` content, allowing attackers to submit arbitrarily large payloads that could exhaust server resources. The fix upgrades Starlette from version 0.49.1 to 0.50.0, where the form parser correctly enforces configured limits for both multipart and URL-encoded content types. This change was applied to `agent/sandbox/u

critical

How Server-Side Request Forgery (SSRF) Happens in Node.js fetch Tools and How to Fix It

A critical Server-Side Request Forgery (SSRF) vulnerability in `plugins/tools/fetch.js` allowed attackers to access internal resources and cloud metadata endpoints by passing arbitrary URLs to the fetch command. The fix adds hostname resolution and private IP range validation before executing any HTTP requests, preventing attackers from targeting internal infrastructure.

critical

How Server-Side Request Forgery (SSRF) happens in Node.js API proxies and how to fix it

A critical SSRF vulnerability was discovered in server.js where the API proxy endpoint constructed target URLs from user-controlled path parameters without validating the final origin. Attackers could use URL encoding tricks like `/api/%2F%2Fevil.com` to redirect proxy requests to arbitrary hosts, potentially accessing cloud metadata services or internal resources. The fix adds origin validation to ensure all proxied requests only reach the intended openrouter.ai upstream.