Skip to content

Commit 999a0b5

Browse files
security(cli): suppress false-positive path-traversal Semgrep findings on the path-containment guard (APS-19008)
semgrep/ci blocked #1141 on 4 path-join-resolve-traversal findings, all on the new path-CONTAINMENT code itself: isPathInsideBase() (securityValidation.js:61-62) and validateBstackJson's resolve (utils.js:42). The path.resolve() calls ARE the anti-traversal guard — each is immediately followed by a containment check (startsWith(base+sep) / isPathInsideBase + .json-extension). Semgrep flags resolve(userInput) without seeing the guard, so these are false positives. Added // nosemgrep on the exact lines with justification (per Security Ops book #68). No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e578fad commit 999a0b5

2 files changed

Lines changed: 3 additions & 0 deletions

File tree

bin/helpers/securityValidation.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ function isPathInsideBase(candidatePath, baseDir) {
5858
if (typeof candidatePath !== 'string' || candidatePath === '') {
5959
return false;
6060
}
61+
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal -- these resolves ARE the traversal guard: the value is normalized here only so the containment check below can reject anything outside `base`.
6162
const base = path.resolve(baseDir || process.cwd());
63+
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal -- see above; resolved path is validated by the startsWith(base) check, not used to read the FS unchecked.
6264
const resolved = path.resolve(base, candidatePath);
6365
// Must be the base itself or a descendant (base + separator prefix).
6466
return resolved === base || resolved.startsWith(base + path.sep);

bin/helpers/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ exports.validateBstackJson = (bsConfigPath) => {
3939
// PR-supplied .js config would run arbitrary code, APS-19008). Also require
4040
// a .json extension and that the file resolves inside the project root so a
4141
// crafted --config-file cannot point outside the project or at a script.
42+
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal -- this resolve IS the traversal guard: the path is normalized here so the .json-extension + isPathInsideBase() containment checks below can reject anything outside the project root.
4243
const resolvedPath = path.resolve(bsConfigPath);
4344
if (path.extname(resolvedPath).toLowerCase() !== ".json") {
4445
return reject(`Invalid browserstack.json file. Error : config file must be a .json file.`);

0 commit comments

Comments
 (0)