domains / / bmad-code-org/bmad-method
Containment and Install Policy
For security-sensitive filesystem and dependency-install flows, treat any path/ref derived from CLI input or manifests as untrusted: (1) parse/validate it, and (2) strictly contain it to the intended root before any filesystem mutation (copy/swap/delete). Also, keep security posture consistent across equivalent install mechanisms.
For security-sensitive filesystem and dependency-install flows, treat any path/ref derived from CLI input or manifests as untrusted: (1) parse/validate it, and (2) strictly contain it to the intended root before any filesystem mutation (copy/swap/delete). Also, keep security posture consistent across equivalent install mechanisms.
Apply these standards:
- Path containment before mutation: Use the project’s existing containment helper (e.g., a
safePathInsideRoot-style check) to reject.., absolute paths, and symlink/escape attempts. Perform the check both for directory targets (e.g., beforeatomicSwapDir) and for each per-file path from manifests before callingfs.rm/fs.copy/staging. - Fail/skip safely: If a validated path check fails, throw
PATH_TRAVERSALfor “should never escape” cases, or skip with a clear warning when removing files discovered in manifests. - Npm install security consistency: If you need to harden dependency installs (e.g., adding/removing
--ignore-scripts), implement it as a deliberate, shared policy across all relevant install paths (installer + skills). Avoid “one-off” flag changes that create inconsistent security behavior.
Minimal example (pattern):
import { safePathInsideRoot } from './fs-safe.mjs';
function rmManifestPath(bmadDir, manifestRelPath) {
const abs = safePathInsideRoot(bmadDir, path.join(bmadDir, manifestRelPath));
return fs.rm(abs, { force: true });
}
// Before swapping/copying an install target:
const safeTargetDir = safePathInsideRoot(bmadDir, targetDir);
await atomicSwapDir(safeTargetDir, stagedDir);