GHSA-2P39-2JF3-FV2Q
Vulnerability from github – Published: 2026-08-20 18:35 – Updated: 2026-08-20 18:35Impact
The HTTP route handler exported by next-video/request-handler — which the README instructs consumers to mount at /api/video — allows an unauthenticated remote attacker to read arbitrary .json files from the production filesystem of any application following the documented setup.
The handler's GET endpoint accepts a url query parameter and uses it to locate and serve a JSON asset descriptor from disk. The only guard between "remote URL" and "local file path" is a regex check for ^https?://. Any value that does not match that prefix is treated as a local path, .json is appended, and the file is read with fs.readFile and returned in the HTTP response — with no authentication, no path canonicalization, and no traversal guard.
On a typical Next.js deployment this exposes, at minimum:
- The Next.js Server Actions AES encryption key (.next/server/server-reference-manifest.json)
- The Next.js Preview/Draft Mode keys (previewModeId, previewModeSigningKey, previewModeEncryptionKey)
- Internal build manifests, route registries, and absolute runtime paths
- Application-specific asset metadata (e.g. Mux uploadId, assetId, playbackId values stored in videos/*.json)
Any application that mounted /api/video following the documented one-liner is affected.
Patches
2.8.1
Workarounds
Until a patched version is available, wrap the exported handler in your own route file and validate the url parameter before passing it through:
- Reject any
urlvalue that does not begin withhttps://, or that does not match a known allowlist of trusted remote hosts. - Alternatively, remove the
/api/videoroute entirely if your application only uses build-timeimportof local video files and does not use<Video src="https://...">with string URLs at runtime.
References
src/request-handler.ts— the vulnerable GET handlersrc/assets.ts—getAssetPath(), where the local-vs-remote branching occurssrc/utils/utils.ts—isRemote(), the sole guard between the two branchessrc/config.ts—loadAsset(), which performs the unconstrainedfs.readFile
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.8.0"
},
"package": {
"ecosystem": "npm",
"name": "next-video"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.8.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54150"
],
"database_specific": {
"cwe_ids": [
"CWE-200"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-20T18:35:11Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Impact\n\nThe HTTP route handler exported by `next-video/request-handler` \u2014 which the README instructs consumers to mount at `/api/video` \u2014 allows an unauthenticated remote attacker to read arbitrary `.json` files from the production filesystem of any application following the documented setup.\n\nThe handler\u0027s `GET` endpoint accepts a `url` query parameter and uses it to locate and serve a JSON asset descriptor from disk. The only guard between \"remote URL\" and \"local file path\" is a regex check for `^https?://`. Any value that does not match that prefix is treated as a local path, `.json` is appended, and the file is read with `fs.readFile` and returned in the HTTP response \u2014 with no authentication, no path canonicalization, and no traversal guard.\n\nOn a typical Next.js deployment this exposes, at minimum:\n- The **Next.js Server Actions AES encryption key** (`.next/server/server-reference-manifest.json`)\n- The **Next.js Preview/Draft Mode keys** (`previewModeId`, `previewModeSigningKey`, `previewModeEncryptionKey`)\n- Internal build manifests, route registries, and absolute runtime paths\n- Application-specific asset metadata (e.g. Mux `uploadId`, `assetId`, `playbackId` values stored in `videos/*.json`)\n\nAny application that mounted `/api/video` following the documented one-liner is affected.\n\n### Patches\n\n2.8.1\n\n### Workarounds\n\nUntil a patched version is available, wrap the exported handler in your own route file and validate the `url` parameter before passing it through:\n\n- Reject any `url` value that does not begin with `https://`, or that does not match a known allowlist of trusted remote hosts.\n- Alternatively, remove the `/api/video` route entirely if your application only uses build-time `import` of local video files and does not use `\u003cVideo src=\"https://...\"\u003e` with string URLs at runtime.\n\n### References\n\n- `src/request-handler.ts` \u2014 the vulnerable GET handler\n- `src/assets.ts` \u2014 `getAssetPath()`, where the local-vs-remote branching occurs\n- `src/utils/utils.ts` \u2014 `isRemote()`, the sole guard between the two branches\n- `src/config.ts` \u2014 `loadAsset()`, which performs the unconstrained `fs.readFile`",
"id": "GHSA-2p39-2jf3-fv2q",
"modified": "2026-08-20T18:35:11Z",
"published": "2026-08-20T18:35:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/muxinc/next-video/security/advisories/GHSA-2p39-2jf3-fv2q"
},
{
"type": "WEB",
"url": "https://github.com/muxinc/next-video/commit/73abf1d534c2ac48db546ecfed0e89cbaf124f6f"
},
{
"type": "PACKAGE",
"url": "https://github.com/muxinc/next-video"
},
{
"type": "WEB",
"url": "https://github.com/muxinc/next-video/releases/tag/v2.8.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "next-video: Unauthenticated arbitrary file read via /api/video request handler"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.