# esbuild@0.28.2 security report (npm)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-10-06T14:16:15.000Z
- Files reviewed: 2
- Findings: 5 medium, 4 low severity findings
- Report: https://security.togoder.click/npm/esbuild@0.28.2
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the npm package esbuild@0.28.2 on Oct 6, 2026. An AI review of 2 source files produced 5 medium, 4 low severity findings. The overall verdict is medium: the findings flag risky but common patterns (dynamic code, unsafe defaults, broad file or network access) rather than confirmed malware.

## Findings

### [medium] Code execution via child_process

Finding ID: `NPS-6BD6E77A0E55`

File: `install.js`

The script uses child_process.execFileSync and execSync to spawn external commands (validateBinaryVersion runs the esbuild binary with --version; installUsingNPM runs 'npm install ...'). While these are expected for an install script, they still execute external binaries/commands.

### [medium] Network download and file write

Finding ID: `NPS-9C470284E469`

File: `install.js`

downloadDirectlyFromNPM fetches a .tgz from registry.npmjs.org and writes the extracted binary to disk with chmod 493. The download is over HTTPS and integrity is checked via SHA-256 against package.json hashes, but it is still remote code/binary fetching.

### [medium] File system manipulation outside package scope

Finding ID: `NPS-B7F4CAF9B2CF`

File: `install.js`

installUsingNPM creates a temporary directory inside the esbuild package directory, runs npm install there, then renames the installed binary into place. applyManualBinaryPathOverride overwrites bin/esbuild and modifies lib/main.js when ESBUILD_BINARY_PATH is set. These write operations are scoped to the package but modify installed files.

### [medium] Environment variable usage

Finding ID: `NPS-F4A7B1218A91`

File: `install.js`

The script reads process.env.ESBUILD_BINARY_PATH and process.env.npm_config_user_agent. If ESBUILD_BINARY_PATH is set and valid, applyManualBinaryPathOverride rewrites package files to execute an arbitrary user-specified binary path. This is a documented feature but can be abused if an attacker controls that env var.

### [medium] Install-time execution

Finding ID: `NPS-C8DD1341969C`

File: `install.js`

All of the above logic runs at module load time (top-level await of checkAndPreparePackage). This is typical for an npm install script, but it means any import of this file triggers network and process execution.

### [low] Process spawning and dynamic binary resolution

Finding ID: `NPS-3BE5C29C929A`

File: `lib/main.js`

The code spawns child processes using child_process.spawn and child_process.execFileSync to run the platform-specific esbuild binary. The binary path is resolved dynamically via generateBinPath(), which enumerates platform-specific packages, checks ESBUILD_BINARY_PATH environment variable, and falls back to copying binaries. While this is legitimate esbuild behavior, the dynamic binary resolution and execution flow is inherent to esbuild's architecture and is a potential vector if the environment variable or package resolution is manipulated.

### [low] Environment variable usage

Finding ID: `NPS-0D0C21FB0753`

File: `lib/main.js`

The code reads process.env.ESBUILD_BINARY_PATH and process.env.ESBUILD_WORKER_THREADS to configure execution. The ESBUILD_BINARY_PATH override allows an attacker with control over the environment to direct execution to an arbitrary binary. This is a documented feature but represents a potential privilege escalation or code execution vector in compromised environments.

### [low] Worker thread and SharedArrayBuffer usage

Finding ID: `NPS-460C68B2D8D9`

File: `lib/main.js`

The code starts a worker thread using the current filename (__filename) and uses SharedArrayBuffer with Atomics for synchronous communication. Worker threads spawn additional processes and evaluate incoming messages. While this is standard for esbuild's synchronous API, it increases the attack surface for code execution if messages can be tampered with.

### [low] Dynamic module resolution

Finding ID: `NPS-DD624D3B86D9`

File: `lib/main.js`

The code uses require.resolve() extensively with computed package names to locate platform-specific binaries. It also attempts to require('pnpapi') and require('worker_threads') dynamically. While legitimate, dynamic require with computed paths can be abused if package resolution is poisoned.

## Files reviewed

- `install.js` (medium): This is the legitimate esbuild install script that downloads and installs the platform-specific binary with SHA-256 integrity verification; no clear malicious patterns were found, but it does perform install-time network fetches, process spawning, and filesystem writes typical of a binary installer.
- `lib/main.js` (medium): The code is the legitimate esbuild packaging layer (version 0.28.2) that does not exhibit malicious patterns, though it does contain dynamic process spawning, environment variable usage, and worker thread creation inherent to its build-tool functionality.

## Version ranges

None of the 2 scanned versions of esbuild are flagged high or critical. The latest scanned version, 0.28.2, is medium risk. Only versions we have scanned are listed; unscanned versions between them are not covered.

- 0.28.2 (`0.28.2`): medium (Code execution via child_process +4 more)
- 0.25.8 – 0.28.1 (`>=0.25.8 <=0.28.1`): not scanned
- 0.24.2 (`0.24.2`): medium (Network download and execution of binary +1 more)

## Scanned versions

- [0.28.2](https://security.togoder.click/npm/esbuild@0.28.2): medium, 2026-10-06T14:16:15.000Z
- [0.24.2](https://security.togoder.click/npm/esbuild@0.24.2): medium, 2026-10-04T16:29:13.000Z

AI analysis is guidance, not a guarantee. Methodology: https://security.togoder.click/methodology
