# node-gyp@12.4.0 security report (npm)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-10-06T14:23:28.000Z
- Files reviewed: 18
- Findings: 5 medium, 27 low severity findings
- Report: https://security.togoder.click/npm/node-gyp@12.4.0
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the npm package node-gyp@12.4.0 on Oct 6, 2026. An AI review of 18 source files produced 5 medium, 27 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] Suspicious symlink creation with external input

Finding ID: `NPS-584998FB514B`

File: `lib/build.js:170`

Creates a symlink named 'python3' in a build directory pointing to the Python interpreter path read from config.gypi. The python path is taken from config.variables.python without validation. If an attacker controls config.gypi (e.g., via a malicious package or repo), they could symlink to an arbitrary executable, which is then prepended to PATH and executed during the build. This is a potential vector for code execution during build.

### [medium] process_spawning

Finding ID: `NPS-C5D163AC5423`

File: `lib/configure.js`

The code spawns a child process using gyp.spawn(python, argv) to run gyp (a build tool). This is expected behavior for node-gyp, but it does execute an external process with arguments derived from configuration. No obvious injection vector is present, but spawning processes is a notable capability.

### [medium] Process spawning / command execution

Finding ID: `NPS-E0471654E994`

File: `lib/find-python.js`

The code uses execFile (via ./util) to spawn processes ('py.exe', 'python3', 'python', or paths derived from environment variables). On Windows, it runs commands through a shell with shell: true, which could allow command injection if environment variables are attacker-controlled (e.g., NODE_GYP_FORCE_PYTHON or PYTHON containing shell metacharacters).

### [medium] Command execution with PowerShell

Finding ID: `NPS-1C323642C54E`

File: `lib/find-visualstudio.js:245`

The code spawns PowerShell via execFile to query Visual Studio installations. While this is expected for node-gyp's VS detection, it uses '-ExecutionPolicy Unrestricted' and dynamically constructs command strings with interpolated values from environment variables (vcInstallDir, SystemRoot). The filterArg built from VCINSTALLDIR is inserted into a PowerShell command string without escaping, which could allow command injection if VCINSTALLDIR is attacker-controlled.

### [medium] Path traversal risk

Finding ID: `NPS-863D19068E7C`

File: `lib/remove.js:27`

The version string from command-line arguments (argv[0] or gyp.opts.target) is used in path.resolve(gyp.devDir, version) before being validated. If semver.parse fails (returns null), the raw version string is used directly. While path.resolve normalizes the path, a version like '../../important-dir' would resolve outside gyp.devDir. However, the subsequent fs.stat check would need to succeed before the rm is executed, and rm is restricted to versionPath. This still constitutes a file system manipulation concern where an attacker-controlled version argument could target directories outside the intended node-gyp development directory for deletion.

### [low] Home directory access

Finding ID: `NPS-15508FC9EF40`

File: `bin/node-gyp.js:20`

Uses os.homedir() to resolve '~' in --devdir and to compute cache paths via env-paths. This is normal behavior for a build tool but does access the user's home directory.

### [low] Process working directory modification

Finding ID: `NPS-9042EA6EAE8E`

File: `bin/node-gyp.js:62`

process.chdir(dir) is called based on user-provided -C/--directory flag. This changes the CWD for the process which can affect subsequent file operations, but is a documented CLI behavior and validated as a directory first.

### [low] Dynamic command dispatch

Finding ID: `NPS-533B0005AE51`

File: `bin/node-gyp.js:85`

prog.commands[command.name] dynamically selects and invokes a command handler based on user-supplied argument (command.name from program args). If command.name is attacker-influenced and 'commands' contains unexpected keys, this could be leveraged for unexpected invocation - though in this context it's the intended CLI dispatch mechanism, not obfuscation.

### [low] Environment variable harvesting

Finding ID: `NPS-9515A5EDD9A2`

File: `bin/node-gyp.js:121`

The errorMessage() function reads and logs npm_package_name and npm_package_version environment variables. While limited to npm package metadata and only on error paths, this is a minor information disclosure pattern that could be expanded in other code paths, and it demonstrates environment variable access behavior.

### [low] Spawning processes with user-controlled input

Finding ID: `NPS-26882B016A59`

File: `lib/build.js:199`

The build function spawns `make` or `msbuild` with argv that may include user-supplied options (gyp.opts.make, gyp.opts.jobs, gyp.opts.solution). While this is typical for a build tool, it allows arbitrary command execution if an attacker can influence these options, e.g., through package.json or environment variables. This is expected behavior for node-gyp but should be noted as a risk in a third-party package context.

### [low] environment_variable_modification

Finding ID: `NPS-F189173A9F92`

File: `lib/configure.js`

The code modifies process.env.PYTHONPATH and process.env.PYTHON, which could affect subsequent subprocesses. This is part of normal node-gyp operation but is a side effect that could potentially be abused in a compromised environment.

### [low] file_system_access

Finding ID: `NPS-97EA9E421F3C`

File: `lib/configure.js`

The code reads files from the node prefix directory (node_version.h) and resolves paths based on user-provided --nodedir, expanding ~ to the home directory. This is expected for node-gyp but allows reading files outside the package scope if a malicious --nodedir is provided.

### [low] dynamic_path_resolution

Finding ID: `NPS-9168E8A765DA`

File: `lib/configure.js`

The code constructs paths using user-controlled input (gyp.opts.nodedir, argv) and resolves them. While not directly malicious, it could be used to access unintended locations if an attacker controls the build arguments.

### [low] Dynamic code execution

Finding ID: `NPS-0B99758DA292`

File: `lib/create-config-gypi.js:18`

The code uses JSON.parse on strings read from files and process.config. This is not eval or Function constructor, so it is safe, but it does parse potentially attacker-controlled config.gypi files. However, JSON.parse itself is not dangerous unless combined with eval. The parsed config is then written to a file in the build directory, which is expected behavior for node-gyp.

### [low] File system manipulation

Finding ID: `NPS-A0C02D4FEB16`

File: `lib/create-config-gypi.js:27`

The code reads from a path derived from nodeDir and writes to buildDir. Both are expected parameters for node-gyp. No traversal outside intended directories is evident, but nodeDir could be user-controlled via --nodedir flag, potentially allowing reading arbitrary config.gypi files. This is by design for node-gyp to support custom Node.js headers.

### [low] Environment variable and credential harvesting

Finding ID: `NPS-FF8A2F9908FA`

File: `lib/create-config-gypi.js:45`

The code accesses process.config and process.arch, but does not read environment variables or credential files like .npmrc, .ssh, etc. The gyp.opts object may contain user-provided command-line options, but these are not exfiltrated.

### [low] Network request with configurable proxy and CA

Finding ID: `NPS-F0D023D25A60`

File: `lib/download.js:6`

The module downloads content from a user-supplied URL using undici fetch. Proxy and CA settings are taken from gyp options or environment variables, which is normal for node-gyp-style tooling. No data is sent to unexpected external servers; requests target the provided URL.

### [low] Environment variable usage

Finding ID: `NPS-6E72DD774629`

File: `lib/download.js:55`

Reads http_proxy, HTTP_PROXY, https_proxy, HTTPS_PROXY to configure proxy support. This is expected behavior for a downloader and does not harvest credentials or secrets.

### [low] File system read

Finding ID: `NPS-31695B56DDF3`

File: `lib/download.js:91`

readCAFile reads a CA certificate file from a path provided via gyp.opts.cafile. This is explicit user configuration, not harvesting of sensitive files like ~/.ssh or cloud credentials.

### [low] Environment variable harvesting

Finding ID: `NPS-F1E18DD4E73E`

File: `lib/find-python.js`

The code reads numerous environment variables (USERNAME, USER, LOCALAPPDATA, SystemDrive, ProgramW6432, ProgramFiles, ProgramFiles(x86), NODE_GYP_FORCE_PYTHON, PYTHON) to construct paths and locate Python executables. While this is expected behavior for a Python finder, it could be abused to gather system/user information if the package were malicious.

### [low] File system path manipulation

Finding ID: `NPS-795582AE76A2`

File: `lib/find-python.js`

The code constructs absolute file paths to Python executables across Program Files and LocalAppData directories and attempts to execute them. If an attacker can place a malicious python.exe in one of these locations, it could lead to arbitrary code execution.

### [low] Environment variable harvesting

Finding ID: `NPS-4B2C0CDF52B2`

File: `lib/find-visualstudio.js:68`

Reads numerous environment variables including VCINSTALLDIR, VSCMD_VER, WindowsSDKVersion, and SystemRoot. These are used for VS detection logic, not exfiltration, but the pattern of environment variable access is present.

### [low] Process spawning

Finding ID: `NPS-BA9A175C4546`

File: `lib/find-visualstudio.js:210`

Uses execFile to spawn powershell.exe with -NoProfile and various commands including Get-VSSetupInstance and Add-Type for loading a local C# file. This is standard node-gyp functionality for locating Visual Studio, but represents a shell/process execution surface.

### [low] Network download with checksum verification

Finding ID: `NPS-A24EED0A20E0`

File: `lib/install.js`

Downloads Node.js development tarballs and Windows node.lib files from release.tarballUrl and related URLs, but verifies content against SHASUMS256.txt checksums. This is expected functionality for node-gyp's install command.

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

Finding ID: `NPS-9A3CA057BB07`

File: `lib/install.js`

Creates and manages directories under gyp.devDir (typically ~/.node-gyp) and os.tmpdir(). Files are extracted from tarballs, with only .h and .gypi files filtered in. This is standard node-gyp behavior for installing dev headers.

### [low] Temp directory cleanup

Finding ID: `NPS-D4921B82D3E4`

File: `lib/install.js`

Uses fs.rm with recursive:true on a temp directory created via mkdtemp, which is properly scoped and cleaned up in a finally block. Not a concern.

### [low] Environment variable harvesting

Finding ID: `NPS-AD5C8C66B803`

File: `lib/node-gyp.js`

The code reads environment variables matching npm_config_* and npm_package_config_node_gyp_* and injects them into options. This is legitimate for node-gyp but could expose secrets if present in environment. However, it only reads and uses them locally, not exfiltrating.

### [low] Spawning child processes

Finding ID: `NPS-06AB73076226`

File: `lib/node-gyp.js`

The spawn method uses childProcess.spawn to execute arbitrary commands. This is expected for node-gyp's build functionality, but could be abused if command/args are attacker-controlled. The code is part of a build tool, so this is intentional behavior.

### [low] Dynamic module loading

Finding ID: `NPS-6EB72FD04A2E`

File: `lib/node-gyp.js`

The constructor dynamically requires command modules based on a fixed list ('./' + command). The commands are from a hardcoded array, so no user input is used for module paths. This is safe.

### [low] Spawning processes or shell commands

Finding ID: `NPS-AA125525466C`

File: `lib/util.js:7`

The execFile function wraps child_process.execFile, which spawns external processes. While this is a legitimate utility used to run reg.exe for Windows registry queries, spawning processes is a red flag that warrants scrutiny.

### [low] Environment variable usage

Finding ID: `NPS-0FAE1019A303`

File: `lib/util.js:14`

regGetValue reads process.env.SystemRoot to construct the path to reg.exe. This is a standard use for locating the Windows directory and is not credential harvesting, but environment variable access is noted.

### [low] File system access

Finding ID: `NPS-873C9439218D`

File: `lib/util.js:63`

findAccessibleSync uses openSync to read files resolved from caller-provided candidates. This is a general-purpose file readability helper and does not target sensitive paths itself, but could be misused by callers.

## Files reviewed

- `bin/node-gyp.js` (medium): The file is the legitimate node-gyp CLI entrypoint; it contains expected CLI dispatch, logging, and directory handling behaviors with no malicious exfiltration, obfuscation, or credential theft patterns.
- `lib/build.js` (medium): The code appears to be a legitimate node-gyp build script with no clear malicious intent, but it creates symlinks based on unvalidated config values and spawns build commands with user-influenced arguments, posing moderate risks if the configuration is attacker-controlled.
- `lib/configure.js` (medium): The code appears to be a legitimate node-gyp configure script with expected process spawning and environment modifications, but no clear malicious patterns such as data exfiltration, credential harvesting, or obfuscated code were detected.
- `lib/find-python.js` (medium): This code appears to be a legitimate Python finder utility (part of node-gyp), but it spawns processes and reads many environment variables, presenting low-to-medium risk if the package or environment is compromised.
- `lib/find-visualstudio.js` (medium): This appears to be legitimate node-gyp Visual Studio detection code, but it contains a potential PowerShell command injection risk via unescaped VCINSTALLDIR interpolation and spawns PowerShell with ExecutionPolicy Unrestricted.
- `lib/node-gyp.js` (medium): The code is a legitimate part of node-gyp with expected build tool functionality; no malicious patterns detected, but it does read environment variables and spawn child processes as part of its normal operation.
- `lib/remove.js` (medium): The remove function may allow deletion of directories outside the intended node-gyp development directory if a malicious version string containing path traversal sequences is supplied.
- `lib/util.js` (medium): The code is a legitimate utility module for spawning processes and reading files, with no evidence of malicious intent, though it does contain process-spawning and file-access primitives that warrant monitoring.
- `eslint.config.js` (safe): No malicious patterns detected
- `lib/clean.js` (safe): No malicious patterns detected
- `lib/create-config-gypi.js` (safe): The code appears to be a legitimate part of node-gyp for generating config.gypi files, with no malicious patterns such as data exfiltration, credential harvesting, or backdoor installation detected.
- `lib/download.js` (safe): The code is a legitimate download helper using undici with proxy/CA configuration and contains no malicious patterns.
- `lib/find-node-directory.js` (safe): Cleared by Jev triage; no further analysis needed
- `lib/install.js` (safe): This is the legitimate node-gyp install.js module which downloads Node.js development files with SHA-256 checksum verification; no malicious patterns detected.
- `lib/list.js` (safe): No malicious patterns detected; the code only reads and lists directory contents within the node-gyp development directory.
- `lib/log.js` (safe): No malicious patterns detected
- `lib/process-release.js` (safe): No malicious patterns detected; the code is a legitimate Node.js release URL resolver from node-gyp with no exfiltration, credential harvesting, obfuscation, or suspicious execution.
- `lib/rebuild.js` (safe): The file is a straightforward node-gyp rebuild helper with no obfuscation, network, filesystem, or process-spawning code; it only queues clean/configure/build tasks.

## Version ranges

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

- 12.4.0 – 13.1.0 (`>=12.4.0 <=13.1.0`): medium (process_spawning +4 more)
- 8.4.1 – 12.2.0 (`>=8.4.1 <=12.2.0`): not scanned

## Scanned versions

- [13.1.0](https://security.togoder.click/npm/node-gyp@13.1.0): medium, 2026-10-06T14:22:46.000Z
- [12.4.0](https://security.togoder.click/npm/node-gyp@12.4.0): medium, 2026-10-06T14:23:28.000Z

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