CVE-2026-49982
tmp: Type-confusion bypass of _assertPath in [email protected] allows path traversal via non-string prefix/postfix/template
tmp is a temporary file and directory creator for node.js. In version 0.2.6, the _assertPath guard added to tmp rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges. This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion. This vulnerability is fixed in 0.2.7.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
8.2
tmp: Type-confusion bypass of _assertPath in [email protected] allows path traversal via non-string prefix/postfix/template
tmp is a temporary file and directory creator for node.js. In version 0.2.6, the _assertPath guard added to tmp rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges. This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion. This vulnerability is fixed in 0.2.7.
- Record
CVE-2026-49982- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-20, CWE-22
- Updated
- 2026-11-02
EUVDEUVD-2026-36265
8.2
tmp is a temporary file and directory creator for node.js. In version 0.2.6, the _assertPath guard added to tmp rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges. This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion. This vulnerability is fixed in 0.2.7.
- Record
EUVD-2026-36265- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-7c78-jf6q-g5cm
8.2
tmp: Type-confusion bypass of _assertPath allows path traversal via non-string prefix/postfix/template
Summary
The _assertPath guard added to [email protected] rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges.
This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion.
Impact
- Arbitrary file creation outside the intended temporary directory, with the running process's filesystem permissions.
- Directory creation outside the intended tree (via
tmp.dir{,Sync}), which can then host a subsequent symlink swap. - File content that the application writes to the returned descriptor lands at the attacker's chosen path. In multi-tenant services this crosses tenant boundaries; in CI/build systems it can write into source trees, build outputs, or web roots.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - score 8.1 (High). Network-reachable when the consumer passes request data unchanged.
Affected versions
tmp >= 0.2.6 (the _assertPath guard introduced by commit 7ef2728 / merged in efa4a06f). Earlier releases are vulnerable to the plain string form (already published as a separate advisory) plus this bypass.
Vulnerable code
lib/tmp.js at tag v0.2.6, commit 41f7159:
// lib/tmp.js:533-539
function _assertPath(path) {
if (path.includes("..")) {
throw new Error("Relative value not allowed");
}
return path;
}
// lib/tmp.js:577-580
options.prefix = _isUndefined(options.prefix) ? '' : _assertPath(options.prefix);
options.postfix = _isUndefined(options.postfix) ? '' : _assertPath(options.postfix);
options.template = _isUndefined(options.template) ? undefined : _assertPath(options.template);
// lib/tmp.js:515-525 - opts.prefix and opts.postfix are stringified by Array.prototype.join
const name = [
opts.prefix ? opts.prefix : 'tmp',
'-',
process.pid,
'-',
_randomChars(12),
opts.postfix ? '-' + opts.postfix : ''
].join('');
return path.join(tmpDir, opts.dir, name);
Root cause: _assertPath assumes its argument is a string. For an Array argument, Array.prototype.includes('..') checks element equality (so ['../escape'].includes('..') is false); for an arbitrary object, Object.prototype.includes does not exist and a duck-typed includes: () => false defeats the check entirely. In both shapes, the subsequent [...].join('') and path.join(...) coerce the value to its underlying string, which still contains ../.
How untrusted data reaches _assertPath
Two production-realistic shapes that yield a non-string prefix/postfix/template:
- JSON request bodies.
express.json()(and any other JSON body parser) preserves the parsed value's type. A body of{"prefix":["../escape"]}reaches the handler as an Array. qs-style bracket-array query strings. Express 4's defaultqsparser turns?prefix[]=../escapeinto['../escape']. The same applies to any framework usingqs(Fastify, Koa with bodyparser, Hapi via configured parsers, etc.).
The consumer pattern is the natural one - forward req.body.prefix directly into tmp.file({ prefix, tmpdir }) with no developer-side coercion. The 0.2.6 release notes describe the guard as preventing prefix/postfix traversal, so consumers reasonably believe the guard covers the typical input flow.
Proof of concept (string vs array)
poc.js (run…
- Record
GHSA-7c78-jf6q-g5cm- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-20, CWE-22
- Updated
- 2026-11-02
NVD
8.2
tmp is a temporary file and directory creator for node.js. In version 0.2.6, the _assertPath guard added to tmp rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges. This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion. This vulnerability is fixed in 0.2.7.
- Record
CVE-2026-49982- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-20, CWE-22
- Updated
- 2026-11-02
OSV
8.2
tmp: Type-confusion bypass of _assertPath in [email protected] allows path traversal via non-string prefix/postfix/template
tmp is a temporary file and directory creator for node.js. In version 0.2.6, the _assertPath guard added to tmp rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges. This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion. This vulnerability is fixed in 0.2.7.
- Record
CVE-2026-49982- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-20, CWE-22
- Updated
- 2026-11-02
OSVGHSA-7c78-jf6q-g5cm
8.2
tmp: Type-confusion bypass of _assertPath allows path traversal via non-string prefix/postfix/template
Summary
The _assertPath guard added to [email protected] rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges.
This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion.
Impact
- Arbitrary file creation outside the intended temporary directory, with the running process's filesystem permissions.
- Directory creation outside the intended tree (via
tmp.dir{,Sync}), which can then host a subsequent symlink swap. - File content that the application writes to the returned descriptor lands at the attacker's chosen path. In multi-tenant services this crosses tenant boundaries; in CI/build systems it can write into source trees, build outputs, or web roots.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - score 8.1 (High). Network-reachable when the consumer passes request data unchanged.
Affected versions
tmp >= 0.2.6 (the _assertPath guard introduced by commit 7ef2728 / merged in efa4a06f). Earlier releases are vulnerable to the plain string form (already published as a separate advisory) plus this bypass.
Vulnerable code
lib/tmp.js at tag v0.2.6, commit 41f7159:
// lib/tmp.js:533-539
function _assertPath(path) {
if (path.includes("..")) {
throw new Error("Relative value not allowed");
}
return path;
}
// lib/tmp.js:577-580
options.prefix = _isUndefined(options.prefix) ? '' : _assertPath(options.prefix);
options.postfix = _isUndefined(options.postfix) ? '' : _assertPath(options.postfix);
options.template = _isUndefined(options.template) ? undefined : _assertPath(options.template);
// lib/tmp.js:515-525 - opts.prefix and opts.postfix are stringified by Array.prototype.join
const name = [
opts.prefix ? opts.prefix : 'tmp',
'-',
process.pid,
'-',
_randomChars(12),
opts.postfix ? '-' + opts.postfix : ''
].join('');
return path.join(tmpDir, opts.dir, name);
Root cause: _assertPath assumes its argument is a string. For an Array argument, Array.prototype.includes('..') checks element equality (so ['../escape'].includes('..') is false); for an arbitrary object, Object.prototype.includes does not exist and a duck-typed includes: () => false defeats the check entirely. In both shapes, the subsequent [...].join('') and path.join(...) coerce the value to its underlying string, which still contains ../.
How untrusted data reaches _assertPath
Two production-realistic shapes that yield a non-string prefix/postfix/template:
- JSON request bodies.
express.json()(and any other JSON body parser) preserves the parsed value's type. A body of{"prefix":["../escape"]}reaches the handler as an Array. qs-style bracket-array query strings. Express 4's defaultqsparser turns?prefix[]=../escapeinto['../escape']. The same applies to any framework usingqs(Fastify, Koa with bodyparser, Hapi via configured parsers, etc.).
The consumer pattern is the natural one - forward req.body.prefix directly into tmp.file({ prefix, tmpdir }) with no developer-side coercion. The 0.2.6 release notes describe the guard as preventing prefix/postfix traversal, so consumers reasonably believe the guard covers the typical input flow.
Proof of concept (string vs array)
poc.js (run…
- Record
GHSA-7c78-jf6q-g5cm- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-20, CWE-22
- Updated
- 2026-11-02
Show 5 moreShow less
OSVUBUNTU-CVE-2026-49982
8.2
tmp is a temporary file and directory creator for node.js. In version 0.2.6, the _assertPath guard added to tmp rejects only string values that contain the substring ... It is bypassed when prefix, postfix, or template is supplied as a non-string value (Array, Buffer, or any object) whose includes('..') returns falsy but whose stringification still contains ../. The value flows through Array.prototype.join/String coercion inside _generateTmpName and path.join(tmpDir, opts.dir, name), producing a final path that escapes tmpdir and creates a file or directory at an attacker-controlled location with the host process's privileges. This affects any application that forwards untrusted request data (a common pattern is JSON body fields or qs-parsed bracket-array query strings such as ?prefix[]=...) into tmp.file, tmp.fileSync, tmp.dir, tmp.dirSync, tmp.tmpName, or tmp.tmpNameSync without explicit type coercion. This vulnerability is fixed in 0.2.7.
- Record
UBUNTU-CVE-2026-49982- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L - Updated
- 2026-11-02
OSVCLSA-2026-1793207018 No score
TuxCare security update for tmp (2 CVEs)
TuxCare rebuilt tmp to address 2 CVEs. Fixed in 0.2.5-tuxcare.1.
- Record
CLSA-2026-1793207018- Updated
- 2026-11-02
OSVCLSA-2026-1793207046 No score
TuxCare security update for tmp (1 CVE)
TuxCare rebuilt tmp to address 1 CVE. Fixed in 0.2.6-tuxcare.1.
- Record
CLSA-2026-1793207046- Updated
- 2026-11-02
OSVCLSA-2026-1793209315 No score
TuxCare security update for tmp (2 CVEs)
TuxCare rebuilt tmp to address 2 CVEs. Fixed in 0.2.4-tuxcare.1.
- Record
CLSA-2026-1793209315- Updated
- 2026-11-02
OSVROOT-APP-NPM-CVE-2026-49982 No score
CVE-2026-49982 in @rootio/tmp - Patched by Root
Root has patched CVE-2026-49982 in the @rootio/tmp package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-CVE-2026-49982- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
tmpnpm |
0.2.6 up to 0.2.7 | 0.2.7 |
tmpTuxCare:npm From an advisory covering 2 CVEs |
0.2.5-tuxcare.0 up to 0.2.5-tuxcare.1, plus listed versions 0.2.5 |
0.2.5-tuxcare.1 |
tmpTuxCare:npm |
0.2.6-tuxcare.0 up to 0.2.6-tuxcare.1, plus listed versions 0.2.6 |
0.2.6-tuxcare.1 |
tmpTuxCare:npm From an advisory covering 2 CVEs |
0.2.4-tuxcare.0 up to 0.2.4-tuxcare.1, plus listed versions 0.2.4 |
0.2.4-tuxcare.1 |
@rootio/tmpRoot:npm |
before 0.2.6-root.io.1 | 0.2.6-root.io.1 |
tmpRoot:npm |
before 0.2.6-aikido.1 | 0.2.6-aikido.1 |
node-tmpUbuntu:16.04:LTS |
All versions, plus listed versions 0.0.25-10.0.28-1 |
None known |
node-tmpUbuntu:18.04:LTS |
All versions, plus listed versions 0.0.31-1 |
None known |
node-tmpUbuntu:20.04:LTS |
All versions, plus listed versions 0.0.33+dfsg-20.1.0+dfsg-20.1.0+dfsg-30.1.0+dfsg-6 |
None known |
node-tmpUbuntu:22.04:LTS |
All versions, plus listed versions 0.2.1+dfsg-10.2.1+dfsg-20.2.1+dfsg+~0.2.2-1 |
None known |
Show 4 moreShow less
| Package | Affected | Fixed |
|---|---|---|
node-tmpUbuntu:24.04:LTS |
All versions, plus listed versions 0.2.2+dfsg+~0.2.3-1 |
None known |
node-tmpUbuntu:25.10 |
All versions, plus listed versions 0.2.2+dfsg+~0.2.3-10.2.2+dfsg+~0.2.3-1.1 |
None known |
node-tmpUbuntu:26.10 |
All versions, plus listed versions 0.2.5+dfsg+~0.2.6-20.2.7+dfsg+~0.2.6-1 |
None known |
node-tmpUbuntu:26.04:LTS |
All versions, plus listed versions 0.2.2+dfsg+~0.2.3-1.10.2.5+dfsg+~0.2.6-10.2.5+dfsg+~0.2.6-2 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| affected, aliases, published, references | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-49982 is a high vulnerability (CVSS 8.2) in Raszi Tmp, published June 11, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.50%, the 42nd percentile. Fixed in tmp 0.2.7.
References
github.com/raszi/node-tmp/security/advisories/GHSA-7c78-jf6q-g5cm
nvd.nist.gov/vuln/detail/CVE-2026-49982
github.com/advisories/GHSA-7c78-jf6q-g5cm
github.com/CVEProject/cvelistV5/tree/main/cves/2026/49xxx/CVE-2026-49982.json
github.com/raszi/node-tmp
ubuntu.com/security/CVE-2026-49982
cve.org/CVERecord?id=CVE-2026-49982
Left out here: the rest of 2 source descriptions. The JSON record has them.