Nov 13, 2026·9 min read·3 visits
Hono versions prior to 4.13.16 fail to validate Origin and Sec-Fetch-Site headers on HTTP POST requests with Content-Type: text/ping. Attackers can exploit this oversight via the HTML <a ping> attribute in Chromium-based browsers to bypass CSRF protection and trigger unauthorized state-modifying actions on endpoints that rely on URL path or query parameters.
CVE-2026-126355 (GHSA-46wx-v44x-9hh2) is a Cross-Site Request Forgery (CSRF) validation bypass in Hono, a web application framework for JavaScript runtimes. Prior to version 4.13.16, Hono's built-in csrf() middleware only evaluated origin headers for requests matching standard HTML form MIME types (application/x-www-form-urlencoded, multipart/form-data, and text/plain). By leveraging the HTML anchor ping attribute in Chromium-based browsers, an attacker can initiate an unprompted, credentialed cross-origin HTTP POST request with Content-Type: text/ping without triggering a CORS preflight request. Because text/ping was omitted from the middleware regular expression, requests bypassed Origin and Sec-Fetch-Site verification, allowing unauthorized state-changing operations.
Hono is a lightweight web application framework designed for JavaScript runtimes, including Cloudflare Workers, Fastly Compute, Deno, Bun, AWS Lambda, and Node.js. It provides built-in middleware modules to handle common security controls, including Cross-Site Request Forgery (CSRF) protection via the hono/csrf package. The csrf() middleware is responsible for inspecting incoming state-changing HTTP requests and rejecting unauthorized cross-origin submissions before they reach application route handlers.
In versions prior to 4.13.16, the csrf() middleware contains a validation bypass classified under CWE-352 (Cross-Site Request Forgery). When evaluating incoming requests, the middleware filters requests by HTTP method and Content-Type header before verifying the Origin and Sec-Fetch-Site headers. The regular expression responsible for matching Content-Type headers only accounted for the three MIME types historically associated with HTML <form> submissions: application/x-www-form-urlencoded, multipart/form-data, and text/plain.
This filtering logic failed to account for HTML5 hyperlink auditing, a browser feature invoked via the ping attribute on HTML anchor (<a>) elements. When a user clicks an anchor tag containing a ping attribute in a Chromium-based browser, the browser dispatches an asynchronous HTTP POST request with Content-Type: text/ping to the specified destination without performing a Cross-Origin Resource Sharing (CORS) preflight (OPTIONS) check.
Because text/ping did not match Hono's Content-Type regular expression, the csrf() middleware treated the request as non-CSRF-capable and skipped Origin and Sec-Fetch-Site validation entirely. Consequently, an attacker can induce an authenticated user to click a link on an external site and trigger unauthorized state-changing operations on vulnerable Hono endpoints.
The root cause of CVE-2026-126355 is an incomplete regular expression allowlist in src/middleware/csrf/index.ts that relies on the assumption that only CORS-safelisted form MIME types can be sent cross-origin without triggering a preflight check. Under the WHATWG Fetch standard, browsers enforce a CORS OPTIONS preflight for cross-origin requests unless the request qualifies as a "simple request" using methods GET, HEAD, or POST alongside application/x-www-form-urlencoded, multipart/form-data, or text/plain.
Based on this specification, Hono's CSRF middleware assumed that any cross-origin POST request carrying a different Content-Type (such as application/json) would require a CORS preflight, which the server would reject unless explicitly permitted by CORS policy. Therefore, Hono selectively enforced origin verification only when isRequestedByFormElementRe matched the incoming Content-Type header:
However, the HTML specification defines hyperlink auditing outside the standard fetch() and XMLHttpRequest request pipelines. When an anchor element includes a ping attribute (<a href="..." ping="https://target.example/api/action">), compliant browsers transmit a background POST request with the static payload PING and the header Content-Type: text/ping. Because this request is initiated directly by browser navigation mechanics rather than client-side JavaScript, the browser does not execute a CORS preflight request.
When this text/ping request arrived at a Hono server prior to version 4.13.16, the middleware first confirmed the method was not GET, HEAD, or OPTIONS. It then evaluated isRequestedByFormElementRe.test('text/ping'), which returned false. Because the conditions inside the if statement were joined by logical AND (&&) operators, the expression short-circuited to false, bypassing both isAllowedSecFetchSite() and isAllowedOrigin() and passing execution directly to await next().
In Hono versions < 4.13.16, the CSRF middleware implementation in src/middleware/csrf/index.ts defined the regular expression isRequestedByFormElementRe to identify requests requiring CSRF protection:
const isSafeMethodRe = /^(GET|HEAD|OPTIONS)$/
// VULNERABLE: Only matches standard HTML form Content-Types, omitting text/ping
const isRequestedByFormElementRe =
/^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)\b/i
export const csrf = (options?: CSRFOptions): MiddlewareHandler => {
return async function csrf(c, next) {
if (
!isSafeMethodRe.test(c.req.method) &&
// Short-circuits to false when Content-Type is 'text/ping'
isRequestedByFormElementRe.test(c.req.header('content-type') || 'text/plain') &&
!(await isAllowedSecFetchSite(c.req.header('sec-fetch-site'), c)) &&
!(await isAllowedOrigin(c.req.header('origin'), c))
) {
return c.text('Forbidden', 403)
}
await next()
}
}In commit bf16471913b5199212dac33f5d170f94745dd26a (released in v4.13.16), the maintainers renamed isRequestedByFormElementRe to isCsrfContentTypeRe and updated the regular expression non-capturing group under the text/ prefix to match both plain and ping:
File: src/middleware/csrf/index.ts
@@ -26,8 +26,8 @@ interface CSRFOptions {
}
const isSafeMethodRe = /^(GET|HEAD|OPTIONS)$/
-const isRequestedByFormElementRe =
- /^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)\b/i
+const isCsrfContentTypeRe =
+ /^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/(?:plain|ping))\b/i
/**
* CSRF Protection Middleware for Hono.
@@ -138,7 +138,7 @@ export const csrf = (options?: CSRFOptions): MiddlewareHandler => {
return async function csrf(c, next) {
if (
!isSafeMethodRe.test(c.req.method) &&
- isRequestedByFormElementRe.test(c.req.header('content-type') || 'text/plain') &&
+ isCsrfContentTypeRe.test(c.req.header('content-type') || 'text/plain') &&
!(await isAllowedSecFetchSite(c.req.header('sec-fetch-site'), c)) &&
!(await isAllowedOrigin(c.req.header('origin'), c))
) {The regular expression uses the leading word boundary anchor ^\b and trailing word boundary \b with the case-insensitive flag i. This ensures that text/ping, Text/Ping, and parameterized headers such as text/ping; charset=utf-8 all match isCsrfContentTypeRe and proceed to Sec-Fetch-Site and Origin verification.
> [!NOTE]
> Fix Completeness Assessment: While expanding the allowlist to include text/ping resolves the hyperlink auditing vector, relying on a blocklist/allowlist of Content-Type values to gate CSRF validation remains fragile if browser specifications introduce additional preflight-exempt MIME types in the future, or if an endpoint accepts requests with an empty or unrecognized Content-Type sent via other browser mechanisms. However, because c.req.header('content-type') || 'text/plain' defaults missing headers to 'text/plain', requests omitting Content-Type entirely are still properly checked.
Exploiting CVE-2026-126355 requires a specific set of environmental and application conditions, reflected in the High Attack Complexity (AC:H) and User Interaction Required (UI:R) metrics of its CVSS v3.1 vector:
ping request always sends the static body PING, the target Hono route cannot rely on structured request bodies (such as parsed JSON or form fields) to determine the action. Instead, the endpoint must execute state-changing logic based solely on the URL path (e.g., POST /api/items/42/delete), query parameters (e.g., POST /api/account?action=deactivate), or ambient session state (e.g., POST /api/session/logout).<a ping> by default. Mozilla Firefox disables hyperlink auditing by default (browser.send_pings = false).ping request to carry the victim's authentication cookies, either the target application's session cookie must be configured with SameSite=None; Secure, or the attacker must host the malicious link on a same-site origin (such as a compromised subdomain sub.target.com targeting api.target.com, where SameSite=Lax cookies are still transmitted on POST requests).Consider a Hono application that exposes a state-changing endpoint protected by csrf():
import { Hono } from 'hono'
import { csrf } from 'hono/csrf'
const app = new Hono()
app.use('*', csrf())
app.post('/api/account/delete', (c) => {
// Performs state mutation based on authenticated session cookie
return c.text('Account deleted')
})
export default appAn attacker hosts the following HTML document on an external origin (https://attacker.example) or a sibling subdomain:
<!DOCTYPE html>
<html>
<body>
<a href="https://attacker.example/landing" ping="https://target.example/api/account/delete">
Continue to Article
</a>
</body>
</html>When an authenticated user clicks the anchor link in a Chromium browser, the browser navigates to https://attacker.example/landing while simultaneously transmitting the following background HTTP request:
POST /api/account/delete HTTP/1.1
Host: target.example
Content-Type: text/ping
Ping-From: https://attacker.example/
Ping-To: https://target.example/api/account/delete
Origin: https://attacker.example
Sec-Fetch-Site: cross-site
Cookie: session_id=VALID_SESSION_TOKEN
Content-Length: 4
PINGOn Hono < 4.13.16, the csrf() middleware inspects Content-Type: text/ping, fails to match isRequestedByFormElementRe, ignores Sec-Fetch-Site: cross-site and Origin: https://attacker.example, and executes the /api/account/delete handler.
The vulnerability carries a CVSS v3.1 base score of 5.3 (Medium) with the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N. The primary impact is to Integrity (I:H), as an attacker can force an authenticated victim to execute arbitrary state-changing POST requests within the scope of the victim's session on vulnerable endpoints.
Confidentiality (C:N) is unaffected because HTML5 hyperlink auditing requests are strictly write-only operations from the initiator's perspective. The browser does not expose the HTTP response headers or body of a ping request to the initiating page's DOM or JavaScript context. Similarly, Availability (A:N) is not directly impacted at the framework level unless the targeted application endpoint itself triggers a resource deletion or service disruption action.
The practical exposure of a Hono deployment depends heavily on cookie policies and API conventions. Modern browsers default unset SameSite cookie attributes to SameSite=Lax, which prevents cookies from being attached to cross-site POST requests, including <a ping>. However, applications that explicitly set SameSite=None; Secure (common in federated login flows, embedded iframes, or cross-domain single-page applications) or applications deployed in multi-tenant subdomain environments (where an attacker controls a sibling subdomain within the same eTLD+1 boundary) remain exposed to exploitation.
The primary remediation is to upgrade the hono package to version 4.13.16 or later, which updates src/middleware/csrf/index.ts to inspect Origin and Sec-Fetch-Site headers on text/ping requests.
npm install hono@^4.13.16
# or
pnpm update hono
# or
bun update honoIf an immediate framework upgrade is not feasible, developers can implement a custom pre-middleware handler to explicitly block or validate text/ping requests before they reach route handlers:
import { createMiddleware } from 'hono/factory'
const blockCrossOriginPing = createMiddleware(async (c, next) => {
const contentType = c.req.header('content-type') || ''
const secFetchSite = c.req.header('sec-fetch-site')
if (/^text\/ping\b/i.test(contentType) && secFetchSite !== 'same-origin') {
return c.text('Forbidden', 403)
}
await next()
})
app.use('*', blockCrossOriginPing)As defense-in-depth measures, engineering teams should also apply the following architectural controls:
SameSite Cookie Policies: Configure session cookies with SameSite=Lax or SameSite=Strict unless cross-site cookie transmission is strictly required by application architecture.POST endpoints that mutate state based solely on URL path or query parameters. Require structured application/json payloads and validate the Content-Type header on the receiving route.CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
hono honojs | < 4.13.16 | 4.13.16 |
| Attribute | Detail |
|---|---|
| Vulnerability ID | CVE-2026-126355 / GHSA-46wx-v44x-9hh2 |
| Weakness Type | CWE-352: Cross-Site Request Forgery (CSRF) |
| CVSS v3.1 Score | 5.3 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N) |
| Attack Vector | Network via HTML <a ping> Hyperlink Auditing (Content-Type: text/ping) |
| Affected Component | hono/csrf Middleware (src/middleware/csrf/index.ts) |
| Affected Versions | Hono < 4.13.16 |
| Patched Version | Hono 4.13.16 |
| CISA KEV Status | Not Listed |
The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
CVE-2026-128067 is a memory corruption vulnerability in Pillow (versions 2.3.0 through 12.3.0) occurring when saving compressed TIFF images via the underlying libtiff encoder. By supplying crafted image geometry tags through exif=, tiffinfo=, or a source TIFF IFD, an attacker can override the scanline dimensions configured in libtiff while Pillow allocates the internal row buffer based strictly on the physical image dimensions. This mismatch induces an out-of-bounds heap read during scanline encoding, and escalates to an out-of-bounds heap write when TIFF Predictor 2 (horizontal differencing) is enabled.
CVE-2026-128066 (GHSA-wqgw-9xfh-qf2g) is a resource allocation vulnerability (CWE-770) in the Python Pillow imaging library affecting versions 1.0 through 12.3.0. The flaw resides in the ImageFileDirectory_v2.load() method within src/PIL/TiffImagePlugin.py, which processes Tag Image File Format (TIFF) structures and Exchangeable Image File Format (EXIF) metadata across multiple container formats. By supplying an image with thousands of IFD tag entries that point to overlapping or identical file offsets, an attacker can trigger quadratic memory amplification (O(N * filesize)). Because the vulnerability occurs during metadata parsing rather than pixel decoding, it bypasses Pillow's built-in decompression bomb protections (Image.MAX_IMAGE_PIXELS).
CVE-2026-126081 is a mass-assignment vulnerability (CWE-915) in the Action Pack component of Ruby on Rails. Prior to versions 8.1.4.1 and 8.0.5.2, the ActionController::Parameters#each_key method was delegated directly to the internal ActiveSupport::HashWithIndifferentAccess instance holding raw request parameters. When invoked with a block, #each_key returned the underlying unpermitted hash rather than the ActionController::Parameters wrapper instance. Applications that pass the return value of #each_key directly into Active Model mass-assignment methods bypass Strong Parameters enforcement, allowing attackers to modify restricted model attributes.
A vulnerability classified under CWE-345 (Insufficient Verification of Data Authenticity) exists in the Active Storage component of Ruby on Rails prior to versions 8.1.4.1 and 8.0.5.2. When Google Cloud Storage (GCS) is configured as the storage backend with the cache_control option enabled, Active Storage switches from GCS V2 signing to V4 signing for direct upload URLs. Because the V4 signing implementation only binds the Cache-Control and Host headers, the Content-Type and Content-MD5 headers remain unsigned. An attacker can modify the Content-Type header during a direct upload request to store HTML or SVG files with active JavaScript on the GCS bucket origin, enabling Service Worker registration and interception of subsequent signed URL responses within the bucket path.
A Cross-Site Scripting (XSS) vulnerability exists in Ruby on Rails Action View prior to versions 8.0.5.2 and 8.1.4.1. When applications use the default HTML5 sanitizer (Rails::HTML5::Sanitizer) with Nokogiri versions prior to 1.19.5, angle brackets (< and >) inside HTML attribute values are serialized unescaped. Action View text helpers—specifically highlight and simple_format—perform string-based manipulations on the sanitized HTML rather than operating on the DOM tree. An unescaped '>' character or a double newline ('\n\n') inside an attribute value causes these helpers to misidentify tag or paragraph boundaries, breaking out of the attribute context and emitting inert attribute contents as live HTML elements in the final html_safe output.
CVE-2026-126070 is a Cross-Site Scripting (XSS) vulnerability in the Action View component of Ruby on Rails. Prior to versions 8.0.5.2 and 8.1.4.1, the strip_tags helper returned sanitized output marked as html_safe without encoding single or double quotation marks. When applications render the output of strip_tags inside quoted HTML attributes in ERB templates, attackers can break out of the attribute context and inject arbitrary HTML attributes or JavaScript event handlers.