DO NOT open a public GitHub issue for security vulnerabilities.
Please report security vulnerabilities by emailing the maintainers directly or using GitHub's private vulnerability reporting feature.
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Initial response: Within 48 hours
- Triage and assessment: Within 5 business days
- Fix deployment: Within 14 days for critical issues
The following are in scope for security reports:
| In Scope | Out of Scope |
|---|---|
CLI code in /bin |
Third-party MCP servers |
Template files in /templates |
User-modified agent files |
| Package distribution integrity | GitHub Copilot vulnerabilities |
| Documentation accuracy for security guidance | VS Code extension issues |
- This package has zero runtime dependencies to minimize attack surface
- Always verify you're installing from the official npm registry
- Check
package-lock.jsonis present and matches expected checksums
The .agent.md files contain instructions that influence AI behavior. Users should:
- Review agent definitions before use in sensitive environments
- Understand that agents have access to tools defined in their frontmatter
- Be aware that
runSubagentallows autonomous agent execution
If using optional MCP servers:
- Only enable servers from trusted sources
- Pin versions in your
mcp.jsonconfiguration - Review what permissions each server requires
- MCP servers can execute code—treat them as you would any executable
The CLI performs file operations (copying templates). It:
- Only writes to the current working directory
- Does not execute any copied files
- Uses Node.js built-in
fsfunctions with no shell execution
The CLI uses child_process.spawn() with shell:true in specific cases. This section documents why, the mitigations in place, and how contributors should handle similar cases.
| Location | Reason | Risk Level |
|---|---|---|
installBacklogCli() |
Cross-platform npm execution (npm.cmd on Windows) | None |
installBeads() |
Cross-platform npm execution (npm.cmd on Windows) | None |
initializeBeads() |
Consistency + shell script wrapper support | Low |
-
No user input in commands: All arguments are hardcoded constants. No user-supplied values are passed to the shell.
-
Path validation: For
initializeBeads(), the executable path comes fromgetBeadsPath()which:- First checks if the binary responds to
--version - Falls back to a hardcoded list of known paths, verified via
existsSync()
- First checks if the binary responds to
-
Input sanitization: CLI arguments are validated before processing:
// Prevent command injection via malformed args if (arg.length > MAX_ARG_LENGTH) { /* reject */ } if (!/^[a-zA-Z0-9-]+$/.test(arg)) { /* reject */ }
-
Allowlist pattern: Only known commands and flags are accepted:
const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h']; const ALLOWED_FLAGS = ['--force', '--skip-backlog', '--skip-mcp', '--skip-beads', '--verbose'];
When adding new shell execution:
- Prefer
shell:false- Use it unless cross-platform execution requires otherwise - Never interpolate user input - If user input must be used, sanitize with allowlists
- Document rationale - Add JSDoc comments explaining why shell:true is necessary
- Validate paths - Use
existsSync()before executing discovered binaries - Hardcode arguments - Prefer
['arg1', 'arg2']over string concatenation
// ✅ SAFE: Hardcoded command and arguments
spawn('npm', ['install', '-g', 'package-name'], { shell: true });
// ✅ SAFE: Validated path, hardcoded argument
const bdPath = getBeadsPath(); // Returns validated path or null
if (bdPath) spawn(bdPath, ['init'], { shell: true });
// ❌ UNSAFE: User input in command
spawn('npm', ['install', userInput], { shell: true }); // NEVER DO THIS
// ❌ UNSAFE: Unvalidated path
spawn(userProvidedPath, ['arg'], { shell: true }); // NEVER DO THISThis repository uses automated security scanning:
- Security alerts: Automatic notifications for vulnerable dependencies
- Version updates: Weekly PRs for outdated npm packages and GitHub Actions
- Grouped updates: Minor/patch updates grouped to reduce PR noise
- Ecosystem coverage: npm (production + dev) and GitHub Actions
- npm audit: Runs on every PR and weekly, fails on high/moderate vulnerabilities
- Gitleaks: Scans for accidentally committed secrets
- CodeQL: Static analysis for JavaScript security issues
- SBOM generation: Creates CycloneDX Software Bill of Materials
Install locally to catch issues before commit:
pip install pre-commit
pre-commit installHooks include:
- Gitleaks: Block commits containing secrets
- File checks: Large files, merge conflicts, private keys
- Markdown linting: Keep docs clean
Location: sbom.json is included in every published npm package.
Format: CycloneDX JSON (industry-standard for supply chain transparency)
The SBOM is automatically regenerated before each npm publish via the prepublishOnly hook.
Regenerate manually:
npm run sbom:generateDirect command (if you need custom options):
npx @cyclonedx/cyclonedx-npm --output-file sbom.json --output-format JSON- Review before running: Inspect template files before using in production
- Pin versions: Use specific versions in
package.jsondependencies - Audit regularly: Run
npm auditon projects using this package - Least privilege: Only enable MCP servers you actually need
- Secret hygiene: Never commit API keys or credentials
- Use pre-commit hooks: Install gitleaks to catch secrets before they're committed
We appreciate security researchers who help keep this project safe. Contributors who report valid vulnerabilities will be acknowledged here (with permission).
"Security isn't paranoia. It's preparation." — Beth