fix(security): resolve open CodeQL path-injection and temp-file alerts (#1322)

Re-establish the path-containment barrier inline at the backup readdir
sink in restoreStackFiles. The sink previously built backupDir through
the getBackupDir helper, whose stack-name validation the static analyzer
does not trace, leaving a flagged path-injection sink. The barrier now
resolves backupDir against its root and asserts containment inline, the
same pattern already used in backupStackFiles. Behavior is unchanged for
valid stack names (already validated one line above by resolveStackDir).

Scope the js/insecure-temporary-file rule out of e2e/** in the CodeQL
config. End-to-end fixtures must seed files into the backend's COMPOSE_DIR
so the API under test can read them back; that path is a fixed location
under /tmp in both CI and local dev, which the rule flags. A randomized
temp directory does not apply because the backend resolves against its own
COMPOSE_DIR. Production code is still analyzed.
This commit is contained in:
Anso
2026-06-05 23:02:08 -04:00
committed by GitHub
parent ce08a593d7
commit 86bfc108ae
2 changed files with 24 additions and 1 deletions
+11 -1
View File
@@ -816,7 +816,17 @@ export class FileSystemService {
const debug = isDebugEnabled();
const t0 = Date.now();
const stackDir = this.resolveStackDir(stackName);
const backupDir = this.getBackupDir(stackName);
// Canonical js/path-injection barrier at the backup read sink: resolve the
// backup dir against its root and confirm containment inline, mirroring
// backupStackFiles. stackName is already validated by resolveStackDir above;
// re-establishing containment at the readdir sink itself lets static
// analysis see the barrier, which it does not credit through the
// getBackupDir helper.
const backupRoot = path.resolve(getBackupBaseDir());
const backupDir = path.resolve(backupRoot, String(this.nodeId), stackName);
if (!backupDir.startsWith(backupRoot + path.sep)) {
throw Object.assign(new Error('Path escapes backup directory'), { code: 'INVALID_PATH' });
}
const items = await fsPromises.readdir(backupDir);
const backedUp = new Set(items);