Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-59895

CVE-2026-59895: Hono Web Framework XSS Vulnerability

CVE-2026-59895 is a cross-site scripting flaw in Hono Web Framework that allows attackers to inject arbitrary markup through untrusted className values. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-59895 Overview

CVE-2026-59895 is a cross-site scripting (XSS) vulnerability in Hono, a web application framework for JavaScript runtimes. The flaw affects the cx() function in hono/css from version 4.0.0 before 4.12.27. The function composes class names from plain strings and marks the result as already escaped, but does not HTML-escape the input. Attackers can supply untrusted className values through a JSX class attribute during server-side rendering to break out of the attribute and inject arbitrary markup. The maintainers resolved the issue in version 4.12.27. This weakness maps to CWE-79: Improper Neutralization of Input During Web Page Generation.

Critical Impact

Untrusted input passed to cx() during server-side rendering enables HTML injection and stored or reflected XSS in applications built with vulnerable Hono versions.

Affected Products

  • Hono web framework versions 4.0.0 through 4.12.26
  • Server-side rendered JSX applications using hono/csscx()
  • Any JavaScript runtime (Node.js, Bun, Deno, Cloudflare Workers) running affected Hono versions

Discovery Timeline

  • 2026-07-08 - CVE-2026-59895 published to NVD
  • 2026-07-08 - Last updated in NVD database

Technical Details for CVE-2026-59895

Vulnerability Analysis

Hono's hono/css helper exposes a cx() utility that composes multiple class names into a single string for use in JSX class attributes. In vulnerable releases, cx() returns its output wrapped as an HtmlEscapedString, signaling the renderer that the value is safe and should not be escaped again. The function performs this marking without first running the input strings through escapeToBuffer. When developers pass user-controlled data — such as a class name derived from a request parameter or a database record — into cx(), characters like ", <, and > pass through untouched.

During server-side rendering, the resulting string is interpolated directly into the HTML attribute. An attacker can close the class attribute, close the enclosing tag, and open new elements or event-handler attributes. This produces reflected or stored XSS depending on how the class name reaches cx().

Root Cause

The root cause is a missing HTML-escape step in the string composition path of cx(). The function trusts caller-supplied class names and marks them as pre-escaped, violating the contract enforced elsewhere in Hono's HTML utilities. The patch adds character validation and routes composed values through escapeToBuffer before marking them safe.

Attack Vector

Exploitation requires an application that forwards attacker-controlled input into cx() and renders the result server-side. User interaction is required to trigger the injected script in a victim's browser, typically by visiting a crafted URL or viewing a page containing stored input. The attack crosses the trust boundary between the server-rendered document and the browser's DOM.

typescript
// Patch excerpt: src/helper/css/common.ts
const isValidClassName = (name: string): boolean => /^-?[_a-zA-Z][_a-zA-Z0-9-]*$/.test(name)

// `<`, `{`, `}` never appear in valid class names but can break out of a <style> element
// or inject a CSS rule when an external cx() class name is used as a selector.
const hasUnsafeSelectorChar = (name: string): boolean => /[<{}]/.test(name)

// CSS-wide keywords that are invalid as @keyframes names per the spec
const RESERVED_KEYFRAME_NAMES = new Set([
  'default',
// Source: https://github.com/honojs/hono/commit/cd3f6f7194f0e5c9d4b26ae0cf232018d0f388fc

The companion change in src/helper/css/index.ts imports escapeToBuffer from ../../utils/html, wiring the escape routine into the render path so unsafe characters are neutralized before the output is marked as escaped.

Detection Methods for CVE-2026-59895

Indicators of Compromise

  • Outbound HTTP requests from rendered pages to unfamiliar domains referenced by injected <script> tags
  • Server logs showing request parameters containing ", <, >, onerror=, or onload= reaching endpoints that render JSX with cx()
  • Unexpected DOM elements or inline event handlers appearing in server-rendered HTML responses

Detection Strategies

  • Perform a dependency audit with npm ls hono or pnpm why hono to locate applications running versions between 4.0.0 and 4.12.26
  • Grep the codebase for cx( calls and trace their arguments back to request-scoped input
  • Run static analysis rules that flag concatenation of untrusted data into class, className, or JSX attributes

Monitoring Recommendations

  • Alert on web application firewall (WAF) hits that show attribute-breakout patterns such as " onerror= in query strings or POST bodies
  • Monitor Content Security Policy (CSP) violation reports for script-src and inline-script breaches on server-rendered routes
  • Capture and review server-rendered HTML responses in canary tests to detect injected markup

How to Mitigate CVE-2026-59895

Immediate Actions Required

  • Upgrade Hono to version 4.12.27 or later across all services and edge deployments
  • Audit application code for any cx() invocation that receives request data, database fields, or other untrusted values
  • Enforce a strict Content Security Policy that blocks inline scripts and unknown script sources as a defense-in-depth control

Patch Information

The fix is available in Hono 4.12.27. See the GitHub Release v4.12.27, the security advisory GHSA-w62v-xxxg-mg59, and the remediation commit cd3f6f7 for full details.

Workarounds

  • Sanitize or allow-list class name input before passing it to cx(), restricting values to the pattern ^-?[_a-zA-Z][_a-zA-Z0-9-]*$
  • Avoid interpolating untrusted data into JSX class attributes; derive class names from server-controlled mappings keyed by validated identifiers
  • Add a CSP Content-Security-Policy header with default-src 'self' and no unsafe-inline to reduce blast radius
bash
# Upgrade Hono to the patched release
npm install hono@4.12.27

# Verify the resolved version in the dependency tree
npm ls hono

# Optional: enforce a strict CSP at the framework level
# app.use('*', async (c, next) => {
#   c.header('Content-Security-Policy', "default-src 'self'; script-src 'self'")
#   await next()
# })

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.