ZeroPath at Black Hat USA 2026

Brief Summary: CVE-2026-49982 Type-Confusion Path Traversal in node-tmp

A short review of CVE-2026-49982, a high-severity type-confusion path traversal in the node-tmp npm package (version 0.2.6) that allows arbitrary file or directory creation outside the intended temporary directory. Includes detection methods and affected version details.

CVE Analysis

10 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-06-11

Brief Summary: CVE-2026-49982 Type-Confusion Path Traversal in node-tmp
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A type-confusion flaw in the popular node-tmp npm package allows attackers to create files and directories at arbitrary filesystem locations by sending non-string values through HTTP request parameters. For any Node.js application that passes user-controlled data into temporary file creation without explicit type coercion, this vulnerability (CVSS 8.2) quietly turns a trusted utility library into a path traversal vector.

The tmp npm package, maintained at raszi/node-tmp, is a widely used library for creating temporary files and directories in Node.js. With 773 GitHub stars and broad adoption as a utility dependency, vulnerabilities in tmp have the potential to cascade across a significant number of downstream applications in the npm ecosystem.

Technical Information

Root Cause: Type-Confusion in _assertPath

The vulnerability resides in the _assertPath guard function added in [email protected]. This guard was designed to prevent path traversal by checking whether the prefix, postfix, template, or dir option values contain the .. substring. The check uses the includes('..') method, which behaves fundamentally differently depending on the type of the receiver.

When a string is passed, String.prototype.includes('..') correctly detects the traversal sequence. But when a non-string value such as an Array, Buffer, or arbitrary object is supplied, the semantics change:

  • For Arrays, Array.prototype.includes('..') checks whether any element is strictly equal to the string '..'. It does not check whether the joined string representation of the array contains ../. For example, an array like ['../escape'] would have includes('..') return false (because no element equals exactly '..'), but when JavaScript implicitly coerces the array to a string via Array.prototype.join or String(), the result contains ../.

  • For Buffers, the includes method searches for byte sequences rather than substring patterns in the stringified output, creating a similar mismatch between the guard's check and the actual path that gets constructed.

Once the non-string value passes the _assertPath guard, it flows into _generateTmpName, where JavaScript's implicit string coercion converts it into a string that does contain ../. This coerced string is then used in path.join(tmpDir, opts.dir, name), producing a final resolved path that escapes the intended temporary directory. The result is file or directory creation at an attacker-controlled location, executed with the privileges of the host Node.js process.

Attack Vectors

The advisory documents two common delivery mechanisms:

  1. JSON request bodies where a field expected to be a string is instead an array. For example: {"prefix": ["../escape"]}. Express's express.json() middleware preserves Array types from parsed JSON, so the array reaches the tmp API intact.

  2. Bracket notation query strings like ?prefix[]=../escape. Libraries like qs (the default query parser in Express 4, Fastify, and Koa) automatically convert bracket notation into arrays, meaning the attacker does not even need to send JSON.

All six affected API functions are susceptible: tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, and tmp.tmpNameSync. Each accepts prefix, postfix, and template options that flow through the vulnerable code path.

Relationship to CVE-2026-44705

A second path traversal vulnerability was reported in the same tmp package under CVE-2026-44705 (GHSA-ph9p-34f9-6g65). While CVE-2026-49982 exploits type confusion (non-string values bypassing a string-specific guard), CVE-2026-44705 involves unsanitized string values for prefix, postfix, or dir options that directly contain path traversal sequences. The two vulnerabilities share the same consequence but use fundamentally different bypass mechanisms.

AttributeCVE-2026-49982CVE-2026-44705
GHSA IDGHSA-7c78-jf6q-g5cmGHSA-ph9p-34f9-6g65
Bypass MechanismType confusion (non-string values)Unsanitized string values
Guard Bypassed_assertPath string includes('..') checkNo guard present for string values
Affected Parametersprefix, postfix, template (as non-strings)prefix, postfix, dir (as strings)
Fixed Version0.2.7Not yet confirmed
CWECWE-20, CWE-22CWE-22

Both vulnerabilities underscore that the input validation in version 0.2.6 was incomplete across both string and non-string input paths. Organizations must address both.

Detection Methods

Detecting exploitation of CVE-2026-49982 is nuanced because the attack specifically bypasses the _assertPath string-level guard. Unlike a standard path traversal that uses ../ in a string, this vulnerability leverages type confusion: the attacker sends a non-string value that passes the guard but still resolves to a traversal path upon stringification. Many conventional path traversal detectors will not catch it.

Software Composition Analysis (SCA)

The most straightforward detection starts at the dependency level. Any project running [email protected] is vulnerable. Security teams should flag this version in their dependency trees using tools like npm audit, Snyk, or Dependabot. Versions prior to 0.2.6 are also vulnerable to the broader path traversal (CVE-2026-44705), so only >=0.2.7 should be considered safe.

Static Code Analysis and Code Auditing

The related GHSA-ph9p-34f9-6g65 advisory provides concrete grep patterns to identify dangerous call sites:

# Search for dangerous tmp usage grep -r "tmp\.file.*prefix.*req\|tmp\.file.*postfix.*req" . grep -r "tmp\.dir.*opts\|tmp\.file.*opts" .

These patterns search for code where request-derived data (req) or generic option objects (opts) are passed into tmp.file or tmp.dir calls. For CVE-2026-49982 specifically, the additional concern is call sites that lack explicit String() coercion before passing values into tmp options. Any code path where req.body.prefix, req.query.prefix, or similar parsed fields flow directly into tmp.file({ prefix }) is exploitable because Express's express.json() preserves Array types, and the default qs parser turns bracket notation query strings into arrays.

Network and API Layer Detection

The GHSA-7c78-jf6q-g5cm advisory documents two attack shapes that defenders should watch for at the network perimeter:

  1. JSON request bodies with non-string types for prefix, postfix, or template fields, for example {"prefix":["../escape"]} where the field is an Array instead of a string.
  2. Bracket notation query strings like ?prefix[]=../escape, which qs-based parsers automatically convert into arrays.

WAF or API gateway rules can be configured to inspect inbound payloads for prefix, postfix, or template fields that contain Arrays or Objects rather than plain strings, and to flag or block bracket notation query parameters targeting these fields.

Runtime Monitoring

The GHSA-ph9p-34f9-6g65 advisory publishes a runtime detection wrapper that monkey-patches tmp.file to flag suspicious usage:

// Log suspicious tmp operations function monitorTmpUsage() { const originalTmpFile = require('tmp').file; require('tmp').file = function(options = {}, callback) { // Check for suspicious patterns const suspicious = [ options.prefix && options.prefix.includes('..'), options.postfix && options.postfix.includes('..'), options.dir && path.isAbsolute(options.dir) ].some(Boolean); if (suspicious) { console.warn('Suspicious tmp usage detected:', options); } return originalTmpFile.call(this, options, callback); }; }

However, there is an important limitation: this monitor uses .includes('..') on the option values, which is the exact same check that _assertPath performs and the exact check that CVE-2026-49982 bypasses. When options.prefix is an Array like ['../escape'], Array.prototype.includes('..') checks for element-level equality (not substring matching), so ['../escape'].includes('..') returns false. To detect the type-confusion vector, this monitor must be extended with a typeof check, flagging any non-string values for prefix, postfix, or template as suspicious.

A more robust approach validates the output path rather than the input options:

// Monitor for files created outside expected temp areas const originalFile = tmp.file; tmp.file = function(options, callback) { return originalFile(options, (err, path, fd, cleanup) => { if (!err && options.tmpdir) { const relative = require('path').relative(options.tmpdir, path); if (relative.startsWith('..')) { console.warn('Path traversal detected:', path); } } return callback(err, path, fd, cleanup); }); };

This output-validation approach is more robust against CVE-2026-49982 because it catches the traversal after stringification, regardless of the input type that caused it.

File System Monitoring

On Linux systems, inotifywait can be used to monitor for unexpected file creation:

# Monitor file creation outside expected temp directories inotifywait -m -r --format '%w%f %e' /tmp /var/tmp | while read file event; do if [[ "$event" == *"CREATE"* && "$file" != /tmp/tmp-* ]]; then echo "Unexpected file creation: $file" fi done

Since exploiting CVE-2026-49982 causes files to be created outside the intended temporary base directory, any file creation in unexpected locations by a Node.js process known to use tmp is a strong indicator.

Log-Based Indicators

Key indicators in application logs include:

  • Log entries showing non-string type values arriving for prefix/postfix/template parameters (e.g., type: array when the application logs the received parameter type).
  • File creation paths that resolve outside the configured temporary base directory.
  • EACCES: permission denied errors on unexpected system paths (e.g., attempts to write under /etc/), which indicate that the traversal succeeded in path construction but was blocked only by OS-level file permissions.

Formal Detection Signatures

At this time, no formalized YARA rules, Sigma rules, Snort/Suricata signatures, or Elastic detection rules specifically targeting CVE-2026-49982 have been published in the major open-source signature repositories.

Affected Systems and Versions

The vulnerability affects tmp npm package version 0.2.6 specifically for the type-confusion bypass described in CVE-2026-49982. The fix is implemented in version 0.2.7.

Versions prior to 0.2.6 lack the _assertPath guard entirely and are vulnerable to the related CVE-2026-44705 (string-based path traversal). Only versions >=0.2.7 should be considered safe against both vulnerabilities.

Any application is affected if it:

  • Uses [email protected] as a direct or transitive dependency.
  • Passes untrusted request data (JSON body fields, query string parameters, or other user-controlled input) into any of the six API functions: tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync.
  • Does not perform explicit type coercion (e.g., String()) on prefix, postfix, or template option values before passing them to tmp.

Applications using Express with express.json() middleware or any framework with qs-based query parsing are particularly at risk, as these automatically preserve Array types from parsed input.

Vendor Security History

The tmp package has disclosed at least two path traversal vulnerabilities within a short timeframe:

  • GHSA-7c78-jf6q-g5cm (CVE-2026-49982): Type-confusion bypass of _assertPath, published June 11, 2026.
  • GHSA-ph9p-34f9-6g65 (CVE-2026-44705): Unsanitized string-valued prefix/postfix/dir options, published May 26, 2026.

The fact that two distinct path traversal flaws were discovered in the same version (0.2.6) suggests that the input validation layer introduced in that version was incomplete. The _assertPath guard addressed one attack vector but left others open. As a single-maintainer open-source project, tmp carries inherent risk: a single maintainer is a bottleneck for security response, and the project's limited contributor base may mean less security review than larger projects receive.

The NVD record for CVE-2026-49982 is currently marked as "Awaiting Enrichment," which is standard for recently published CVEs. The CVSS score of 8.2 originates from the GitHub Security Advisory rather than NIST's formal assessment.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Jira
  • Linear
  • Slack
  • Security Compass
Security magnifying glass visualization