Skip to content

Commit 7ef2728

Browse files
committed
Check for relative values
1 parent 3d2fe38 commit 7ef2728

2 files changed

Lines changed: 44 additions & 5 deletions

File tree

lib/tmp.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,19 @@ function _generateTmpName(opts) {
525525
return path.join(tmpDir, opts.dir, name);
526526
}
527527

528+
/**
529+
* Check the prefix and postfix options
530+
*
531+
* @private
532+
*/
533+
function _assertPath(path) {
534+
if (path.includes("..")) {
535+
throw new Error("Relative value not allowed");
536+
}
537+
538+
return path;
539+
}
540+
528541
/**
529542
* Asserts and sanitizes the basic options.
530543
*
@@ -539,8 +552,9 @@ function _assertOptionsBase(options) {
539552

540553
// must not fail on valid .<name> or ..<name> or similar such constructs
541554
const basename = path.basename(name);
542-
if (basename === '..' || basename === '.' || basename !== name)
555+
if (basename === '..' || basename === '.' || basename !== name) {
543556
throw new Error(`name option must not contain a path, found "${name}".`);
557+
}
544558
}
545559

546560
/* istanbul ignore else */
@@ -561,8 +575,9 @@ function _assertOptionsBase(options) {
561575
options.unsafeCleanup = !!options.unsafeCleanup;
562576

563577
// for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to
564-
options.prefix = _isUndefined(options.prefix) ? '' : options.prefix;
565-
options.postfix = _isUndefined(options.postfix) ? '' : options.postfix;
578+
options.prefix = _isUndefined(options.prefix) ? '' : _assertPath(options.prefix);
579+
options.postfix = _isUndefined(options.postfix) ? '' : _assertPath(options.postfix);
580+
options.template = _isUndefined(options.template) ? undefined : _assertPath(options.template);
566581
}
567582

568583
/**
@@ -578,7 +593,7 @@ function _getRelativePath(option, name, tmpDir, cb) {
578593

579594
const relativePath = path.relative(tmpDir, resolvedPath);
580595

581-
if (!resolvedPath.startsWith(tmpDir)) {
596+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
582597
return cb(new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`));
583598
}
584599

@@ -597,7 +612,7 @@ function _getRelativePathSync(option, name, tmpDir) {
597612
const resolvedPath = _resolvePathSync(name, tmpDir);
598613
const relativePath = path.relative(tmpDir, resolvedPath);
599614

600-
if (!resolvedPath.startsWith(tmpDir)) {
615+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
601616
throw new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`);
602617
}
603618

test/GHSA-ph9p-34f9-6g65-test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const assert = require('assert');
2+
const tmp = require('../lib/tmp');
3+
4+
describe('GHSA-ph9p-34f9-6g65', function () {
5+
describe('#fileSync with attacker `prefix`', function () {
6+
it('should not allow such prefixes', function (done) {
7+
assert.throws(function () {
8+
tmp.fileSync({ prefix: "../foo"});
9+
}, new RegExp('^Error: Relative value not allowed'));
10+
11+
done();
12+
});
13+
});
14+
15+
describe('#fileSync with attacker `postfix`', function () {
16+
it('should not allow such prefixes', function (done) {
17+
assert.throws(function () {
18+
tmp.fileSync({ postfix: "../foo"});
19+
}, new RegExp('^Error: Relative value not allowed'));
20+
21+
done();
22+
});
23+
});
24+
});

0 commit comments

Comments
 (0)