Skip to content

Commit f4611b0

Browse files
committed
chore: add security scanning and enforce no-npx rule
- Add ecc-agentshield as pinned devDep for Claude Code config scanning - Add `pnpm run security` script (agentshield + zizmor) - Add /security-scan command for Claude - Add npx/dlx/yarn-dlx check to pre-commit hook - Add NEVER npx/dlx rule to CLAUDE.md ABSOLUTE RULES - Remove dead .husky/security-checks.sh (duplicate of .git-hooks/pre-commit)
1 parent c403600 commit f4611b0

File tree

9 files changed

+571
-125
lines changed

9 files changed

+571
-125
lines changed

.claude/commands/security-scan.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Run a security scan of the project via `pnpm run security`, or manually:
2+
3+
## 1. Claude Code configuration security
4+
5+
Run `pnpm exec agentshield scan` to check `.claude/` for:
6+
- Hardcoded secrets in CLAUDE.md and settings
7+
- Overly permissive tool allow lists (e.g. `Bash(*)`)
8+
- Prompt injection patterns in agent definitions
9+
- Command injection risks in hooks
10+
- Risky MCP server configurations
11+
12+
## 2. GitHub Actions workflow security
13+
14+
Run `zizmor .github/` to scan all workflows for:
15+
- Unpinned actions (should use full SHA, not tags)
16+
- Secrets used outside `env:` blocks
17+
- Injection risks from untrusted inputs
18+
- Overly permissive permissions
19+
20+
If zizmor is not installed, skip with a message. Install via `brew install zizmor` or see https://docs.zizmor.sh/installation/.
21+
22+
Report all findings with severity levels. Fix CRITICAL and HIGH findings immediately.

.git-hooks/pre-commit

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ for file in $STAGED_FILES; do
112112
fi
113113
done
114114

115+
# Check for npx/dlx usage (use pnpm exec or pnpm run instead).
116+
printf "Checking for npx/dlx usage...\n"
117+
for file in $STAGED_FILES; do
118+
if [ -f "$file" ]; then
119+
# Skip node_modules, lockfiles, and this hook itself.
120+
if echo "$file" | grep -qE 'node_modules/|pnpm-lock\.yaml|\.git-hooks/'; then
121+
continue
122+
fi
123+
124+
if grep -nE '\bnpx\b|\bpnpm dlx\b|\byarn dlx\b' "$file" 2>/dev/null | grep -v '# zizmor:' | grep -q .; then
125+
printf "${RED}✗ ERROR: npx/dlx usage found in: $file${NC}\n"
126+
grep -nE '\bnpx\b|\bpnpm dlx\b|\byarn dlx\b' "$file" | grep -v '# zizmor:' | head -3
127+
printf "Use 'pnpm exec <package>' or 'pnpm run <script>' instead.\n"
128+
ERRORS=$((ERRORS + 1))
129+
fi
130+
fi
131+
done
132+
115133
if [ $ERRORS -gt 0 ]; then
116134
printf "\n"
117135
printf "${RED}✗ Security check failed with $ERRORS error(s).${NC}\n"

.husky/security-checks.sh

Lines changed: 0 additions & 125 deletions
This file was deleted.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
- Always prefer editing existing files
7070
- Forbidden to create docs unless requested
7171
- Required to do exactly what was asked
72+
- 🚨 **NEVER use `npx`, `pnpm dlx`, or `yarn dlx`** — use `pnpm exec <package>` for devDep binaries, or `pnpm run <script>` for package.json scripts. If a tool is needed, add it as a pinned devDependency first.
7273

7374
## ROLE
7475

external-tools.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"zizmor": {
3+
"description": "GitHub Actions security linter",
4+
"type": "github-release",
5+
"repository": "zizmorcore/zizmor",
6+
"version": "1.23.1",
7+
"binary": "zizmor",
8+
"assets": {
9+
"darwin-arm64": {
10+
"asset": "zizmor-aarch64-apple-darwin.tar.gz",
11+
"sha256": "2632561b974c69f952258c1ab4b7432d5c7f92e555704155c3ac28a2910bd717"
12+
},
13+
"darwin-x64": {
14+
"asset": "zizmor-x86_64-apple-darwin.tar.gz",
15+
"sha256": "89d5ed42081dd9d0433a10b7545fac42b35f1f030885c278b9712b32c66f2597"
16+
},
17+
"linux-arm64": {
18+
"asset": "zizmor-aarch64-unknown-linux-gnu.tar.gz",
19+
"sha256": "3725d7cd7102e4d70827186389f7d5930b6878232930d0a3eb058d7e5b47e658"
20+
},
21+
"linux-x64": {
22+
"asset": "zizmor-x86_64-unknown-linux-gnu.tar.gz",
23+
"sha256": "67a8df0a14352dd81882e14876653d097b99b0f4f6b6fe798edc0320cff27aff"
24+
},
25+
"win32-x64": {
26+
"asset": "zizmor-x86_64-pc-windows-msvc.zip",
27+
"sha256": "33c2293ff02834720dd7cd8b47348aafb2e95a19bdc993c0ecaca9c804ade92a"
28+
}
29+
}
30+
}
31+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
"package-npm-publish": "node scripts/npm/publish-npm-packages.mjs",
4141
"perf": "node scripts/perf.mjs",
4242
"precommit": "pnpm run check --staged",
43+
"security": "agentshield scan && { command -v zizmor >/dev/null && zizmor .github/ || echo 'zizmor not installed — run pnpm run setup to install'; }",
44+
"setup": "node scripts/setup.mjs",
4345
"prepare": "husky && pnpm run build",
4446
"prepublishOnly": "echo 'ERROR: Use GitHub Actions workflow for publishing' && exit 1",
4547
"publish": "node scripts/publish.mjs",
@@ -91,6 +93,7 @@
9193
"del-cli": "catalog:",
9294
"dev-null-cli": "catalog:",
9395
"didyoumean2": "catalog:",
96+
"ecc-agentshield": "catalog:",
9497
"esbuild": "catalog:",
9598
"eta": "catalog:",
9699
"fast-glob": "catalog:",

0 commit comments

Comments
 (0)