Jan 27, 2026·5 min read·40 visits
Hono's static asset adapter used a logical OR operator (`||`) to fallback to the raw request path if a file wasn't found in the manifest. This allowed attackers to request any key present in the Cloudflare Workers KV namespace, potentially exposing internal configuration or secrets if they shared the same storage bucket as your cat photos.
A logic flaw in Hono's `serve-static` middleware for Cloudflare Workers allowed attackers to bypass the asset manifest and read arbitrary keys from the underlying KV storage. It turns out that a convenient fallback mechanism is indistinguishable from a gaping security hole.
Serverless environments like Cloudflare Workers are brilliant for compute, but they are notoriously awkward when it comes to the simple act of serving a JPEG. You don't have a filesystem. You have a distributed Key-Value (KV) store that pretends to be a filesystem. Enter Hono, the lightweight framework designed to make this headache go away.
Hono's serve-static middleware is the bridge. It takes a URL request (like /images/logo.png), looks up that path in a generated ASSET_MANIFEST (a JSON map created at build time), and finds the corresponding unique key in the KV store (something like logo.a1b2c3d4.png). It’s a clean, efficient abstraction.
But here is the rub: abstractions leak. When you rely on a middleware to decide what is public and what is private based solely on a lookup table, the logic governing that lookup had better be bulletproof. In CVE-2026-24473, that logic was about as bulletproof as a wet paper towel.
The vulnerability resides in the classic developer impulse to be 'helpful' or 'flexible'. In the Cloudflare Workers adapter, the code needs to translate a request path into a KV key. The developers anticipated a scenario where a user might request a path that exactly matches a KV key, even if it wasn't explicitly listed in the build-time manifest.
So, they implemented a fallback. If the requested path wasn't found in the ASSET_MANIFEST, the code shrugged and said, "Eh, maybe the path is the key?" and tried to fetch it anyway. This turned the middleware from a strict whitelist (only serve what is in the manifest) into a 'try everything' proxy.
This is a textbook example of fail-open logic. By allowing the raw user input to be used directly as a lookup key for the storage backend, the application implicitly trusted that the user would only ask for things they were supposed to see. In the security world, we call this 'optimism', and it is usually fatal.
Let's look at the smoking gun. The vulnerability lived in src/adapter/cloudflare-workers/utils.ts. It’s almost poetic how small the bug is.
// The Vulnerable Logic
export const getContentFromKVAsset = async (
path: string,
options?: Partial<ServeStaticOptions>
) => {
const ASSET_MANIFEST = options?.manifest || __STATIC_CONTENT_MANIFEST
// HERE IS THE BUG:
const key = ASSET_MANIFEST[path] || path
if (!key) {
return null
}
// ... fetch content from KV using 'key' ...
}Do you see it? const key = ASSET_MANIFEST[path] || path. That double pipe || operator is doing a lot of heavy lifting. It says: "If the path is in the manifest, use the mapped key. Otherwise, just use the path itself."
An attacker requests /secrets.json. The manifest obviously doesn't have an entry for /secrets.json. The code evaluates ASSET_MANIFEST['/secrets.json'], gets undefined, hits the || operator, and sets key to '/secrets.json'. It then happily queries the KV store for that key. If your build process accidentally uploaded a config file to the KV store, or if you share the KV namespace with other application logic, Hono just served it on a silver platter.
Exploiting this requires a bit of guessing, but in the world of Cloudflare Workers, namespaces are often reused to save money or simplify config. A developer might create a single KV namespace called MY_APP_DATA and throw everything in there: static assets, session data, and feature flags.
The Attack Chain:
.env, config.json, manifest.json, __STATIC_CONTENT_MANIFEST.GET /config.json.
config.json as the KV key.This bypasses the entire concept of the ASSET_MANIFEST acting as an access control list. It essentially turns the serve-static middleware into a generic Key-Value gateway for anyone with a web browser.
The fix is as simple as the bug. The Hono team removed the fallback logic. If it's not in the manifest, it doesn't exist. Period.
Here is the diff from commit cf9a78db4d0a19b117aee399cbe9d3a6d9bfd817:
--- a/src/adapter/cloudflare-workers/utils.ts
+++ b/src/adapter/cloudflare-workers/utils.ts
@@ -36,7 +36,7 @@ export const getContentFromKVAsset = async (
ASSET_NAMESPACE = __STATIC_CONTENT
}
- const key = ASSET_MANIFEST[path] || path
+ const key = ASSET_MANIFEST[path]
if (!key) {
return null
}By removing || path, the variable key becomes undefined if the lookup fails. The subsequent check if (!key) return null triggers, and the request harmlessly 404s. This restores the 'Default Deny' posture that security components should have had from the start.
CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Hono Honojs | < 4.11.7 | 4.11.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-200 / CWE-668 |
| CVSS v4.0 | 6.3 (Medium) |
| Attack Vector | Network |
| Privileges Required | None |
| Impact | Information Disclosure |
| Patch Status | Released (v4.11.7) |
Exposure of Resource to Wrong Sphere
netfoil, an allowlist-based DNS proxy, failed to sanitize ALPN fields parsed from untrusted DNS-over-HTTPS (DoH) HTTPS Resource Records. This allowed attackers to inject ANSI escape sequences into log files or trigger Denial of Service (DoS) via uncontrolled memory allocations.
An issue was discovered in the tokio-postgres library for Rust prior to version 0.7.18. A trust assumption mismatch between the PostgreSQL protocol messages sent by a server and how they are parsed and indexed by the client-side library allows a rogue or compromised database server to trigger a Denial of Service (DoS) crash via an unhandled out-of-bounds slice indexing panic.
CVE-2026-14669 is a critical heap-based buffer overflow vulnerability in PostgreSQL's date/time formatting function to_char(timestamptz). The flaw arises from unsafe copying of user-controlled timezone abbreviations into a fixed-size internal buffer. An authenticated database user can trigger this issue by setting a long POSIX timezone abbreviation containing custom formatting, allowing them to overwrite adjacent heap structures and hijack execution control to achieve remote code execution (RCE) with the privileges of the 'postgres' operating system user.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.