permission: improve path traversal protection
Always use the original implementation of pathModule.resolve. If the application overwrites the value of pathModule.resolve with a custom implementation, it should not have any effect on the permission model. PR-URL: https://github.com/nodejs-private/node-private/pull/456 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> CVE-ID: CVE-2023-39331
This commit is contained in:
parent
3b23b2ee53
commit
32bcf4ca27
@ -708,12 +708,13 @@ const validatePath = hideStackFrames((path, propName = 'path') => {
|
|||||||
// TODO(rafaelgss): implement the path.resolve on C++ side
|
// TODO(rafaelgss): implement the path.resolve on C++ side
|
||||||
// See: https://github.com/nodejs/node/pull/44004#discussion_r930958420
|
// See: https://github.com/nodejs/node/pull/44004#discussion_r930958420
|
||||||
// The permission model needs the absolute path for the fs_permission
|
// The permission model needs the absolute path for the fs_permission
|
||||||
|
const resolvePath = pathModule.resolve;
|
||||||
function possiblyTransformPath(path) {
|
function possiblyTransformPath(path) {
|
||||||
if (permission.isEnabled()) {
|
if (permission.isEnabled()) {
|
||||||
if (typeof path === 'string') {
|
if (typeof path === 'string') {
|
||||||
return pathModule.resolve(path);
|
return resolvePath(path);
|
||||||
} else if (Buffer.isBuffer(path)) {
|
} else if (Buffer.isBuffer(path)) {
|
||||||
return Buffer.from(pathModule.resolve(path.toString()));
|
return Buffer.from(resolvePath(path.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
|
14
test/fixtures/permission/fs-traversal.js
vendored
14
test/fixtures/permission/fs-traversal.js
vendored
@ -6,6 +6,10 @@ const assert = require('assert');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
// This should not affect how the permission model resolves paths.
|
||||||
|
const { resolve } = path;
|
||||||
|
path.resolve = (s) => s;
|
||||||
|
|
||||||
const blockedFolder = process.env.BLOCKEDFOLDER;
|
const blockedFolder = process.env.BLOCKEDFOLDER;
|
||||||
const allowedFolder = process.env.ALLOWEDFOLDER;
|
const allowedFolder = process.env.ALLOWEDFOLDER;
|
||||||
const traversalPath = allowedFolder + '../file.md';
|
const traversalPath = allowedFolder + '../file.md';
|
||||||
@ -27,7 +31,7 @@ const bufferTraversalPath = Buffer.from(allowedFolder + '../file.md');
|
|||||||
}, common.expectsError({
|
}, common.expectsError({
|
||||||
code: 'ERR_ACCESS_DENIED',
|
code: 'ERR_ACCESS_DENIED',
|
||||||
permission: 'FileSystemWrite',
|
permission: 'FileSystemWrite',
|
||||||
resource: path.toNamespacedPath(path.resolve(traversalPath)),
|
resource: path.toNamespacedPath(resolve(traversalPath)),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +43,7 @@ const bufferTraversalPath = Buffer.from(allowedFolder + '../file.md');
|
|||||||
}, common.expectsError({
|
}, common.expectsError({
|
||||||
code: 'ERR_ACCESS_DENIED',
|
code: 'ERR_ACCESS_DENIED',
|
||||||
permission: 'FileSystemRead',
|
permission: 'FileSystemRead',
|
||||||
resource: path.toNamespacedPath(path.resolve(traversalPath)),
|
resource: path.toNamespacedPath(resolve(traversalPath)),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +55,7 @@ const bufferTraversalPath = Buffer.from(allowedFolder + '../file.md');
|
|||||||
}, common.expectsError({
|
}, common.expectsError({
|
||||||
code: 'ERR_ACCESS_DENIED',
|
code: 'ERR_ACCESS_DENIED',
|
||||||
permission: 'FileSystemWrite',
|
permission: 'FileSystemWrite',
|
||||||
resource: path.resolve(traversalFolderPath + 'XXXXXX'),
|
resource: resolve(traversalFolderPath + 'XXXXXX'),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +67,7 @@ const bufferTraversalPath = Buffer.from(allowedFolder + '../file.md');
|
|||||||
}, common.expectsError({
|
}, common.expectsError({
|
||||||
code: 'ERR_ACCESS_DENIED',
|
code: 'ERR_ACCESS_DENIED',
|
||||||
permission: 'FileSystemWrite',
|
permission: 'FileSystemWrite',
|
||||||
resource: path.resolve(traversalFolderPath + 'XXXXXX'),
|
resource: resolve(traversalFolderPath + 'XXXXXX'),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +79,7 @@ const bufferTraversalPath = Buffer.from(allowedFolder + '../file.md');
|
|||||||
}, common.expectsError({
|
}, common.expectsError({
|
||||||
code: 'ERR_ACCESS_DENIED',
|
code: 'ERR_ACCESS_DENIED',
|
||||||
permission: 'FileSystemRead',
|
permission: 'FileSystemRead',
|
||||||
resource: path.resolve(traversalPath),
|
resource: resolve(traversalPath),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user