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
•Technically reviewed by Anupam Mediratta•Published August 28, 2026•Reviewed 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

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.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #75

Related Articles

medium

path-to-regexp 0.1.12 DoS: Catastrophic Backtracking on Malformed URL

path-to-regexp version 0.1.12 contains a regular expression engine vulnerability where maliciously crafted URL parameters trigger exponential backtracking, causing CPU exhaustion and service unavailability. Upgrading to version 0.1.13 eliminates the vulnerable pattern from the parsing logic.

critical

CVE-2026-59873: node-tar 7.5.11 DoS via Crafted Gzip Bomb

node-tar versions 7.5.11 through 7.5.18 are vulnerable to a denial-of-service attack through maliciously crafted gzip archives that decompress to disproportionately large sizes. An attacker can exploit this to exhaust memory and CPU resources by submitting a small, highly compressed archive that expands beyond configured limits during extraction.

high

MapManager.get() Race Condition Duplicates API Requests

The MapManager's `get(mapUid, cache)` method used a check-then-act pattern that permitted multiple concurrent requests to pass the cache miss check simultaneously, triggering redundant API calls and risking cache corruption. The fix introduces a `_pending` promise map to deduplicate in-flight fetches for identical map UIDs.

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.