
Cloud Vulnerability DB
A community-led vulnerabilities database
When run_worker_first is enabled to put static assets behind the middleware, @opennextjs/cloudflare serves public files through the Workers assets binding (env.ASSETS.fetch). The binding can serve a public file at other paths than its exact path:
html_handling setting, which defaults to auto-trailing-slash (e.g. /protected/handbook for public/protected/handbook.html),public/index.html for any missing file with not_found_handling: "single-page-application",/protected/%2Fhandbook.html to /protected/handbook.html).
The middleware only runs for the requested path, so a matcher or pathname check written for /protected/handbook.html never applies. An unauthenticated client can read the protected public file.
Next.js only serves public files at their exact path.The asset resolver (packages/cloudflare/src/api/overrides/asset-resolver/index.ts) is called by the routing layer after the middleware. It fetches the requested path from the binding, which follows redirects by default:
const url = new URL(event.rawPath, "https://assets.local");
const response = await ASSETS.fetch(url, { headers, method });With the default html_handling: "auto-trailing-slash", the binding returns:
| Request | Served file |
|---|---|
/handbook | public/handbook.html |
/board-pack/ (and /board-pack, after a redirect) | public/board-pack/index.html |
/secret/index.html, when it does not exist | public/secret.html, after a redirect to /secret |
/notes.htm (also /notes.HTML), when it does not exist | public/notes.htm.html (public/notes.HTML.html) |
With not_found_handling: "single-page-application", the binding serves public/index.html for any missing file. | |
With any configuration (including html_handling: "none"), the binding redirects a path to its canonical encoding: /protected/%2Fhandbook.html is redirected to /protected/handbook.html and the resolver served public/protected/handbook.html. The middleware matcher sees /protected//handbook.html and does not run. Redirects from _redirects rules are followed the same way. | |
The middleware runs for the requested path only. A guard on the file's own URL does not match these paths. That covers matchers such as "/handbook.html", "/board-pack/:path+" or "/secret.html", and pathname checks such as pathname === "/handbook.html" or pathname.endsWith(".html"). | |
The encoding redirects also bypass directory guards: /%2Fprotected/handbook.html is redirected to /protected/handbook.html, while the middleware sees //protected/handbook.html, which matches neither "/protected/:path*" nor pathname.startsWith("/protected/"). | |
When run_worker_first is not enabled (the default), assets are served before the Worker runs and are never protected by the middleware. That limitation is documented and is not covered by this advisory. |
An application is affected when all of the following are true:
run_worker_first is set to true (or matches the files) in the assets section of the wrangler config, to protect public files with the middleware.public/.matcher or pathname check).
Any file can be read through the encoding redirects. HTML files can also be read through the html_handling aliases unless html_handling is "none", and public/index.html through the "single-page-application" fallback.
An unauthenticated attacker can then read the protected files.Medium (CVSS 3.1: 5.9)
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
_redirects rules) are returned to the client instead of being followed, so that the middleware runs for the target.run_worker_first is enabled, the build fails unless the assets section of the wrangler config has:"html_handling": "none",
"not_found_handling": "none" // or "404-page"With these values the assets binding only serves files at their exact path, like Next.js. Apps using run_worker_first must update their wrangler config, the build error explains how.
There is no complete workaround without upgrading: setting "html_handling": "none" and "not_found_handling": "none" removes the aliases, but the redirects of the binding (e.g. /protected/%2Fhandbook.html) are still followed on unpatched versions.
Don't keep protected files in public/. Serve them from a route handler that checks authorization.
not_found_handling): https://developers.cloudflare.com/workers/static-assets/routing/run_worker_first: https://developers.cloudflare.com/workers/static-assets/binding/#run_worker_firstSource: NVD
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."