@nerviq/cli 1.18.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -23
- package/README.md +2 -2
- package/bin/cli.js +130 -130
- package/package.json +1 -1
- package/src/activity.js +1039 -1039
- package/src/adoption-advisor.js +299 -299
- package/src/aider/config-parser.js +166 -166
- package/src/aider/context.js +158 -158
- package/src/aider/deep-review.js +316 -316
- package/src/aider/domain-packs.js +303 -303
- package/src/aider/freshness.js +93 -93
- package/src/aider/governance.js +253 -253
- package/src/aider/interactive.js +334 -334
- package/src/aider/mcp-packs.js +329 -329
- package/src/aider/patch.js +214 -214
- package/src/aider/plans.js +186 -186
- package/src/aider/premium.js +360 -360
- package/src/aider/setup.js +404 -404
- package/src/aider/techniques.js +16 -16
- package/src/analyze.js +951 -951
- package/src/anti-patterns.js +485 -485
- package/src/audit/instruction-files.js +180 -180
- package/src/audit/recommendations.js +577 -577
- package/src/auto-suggest.js +154 -154
- package/src/badge.js +13 -13
- package/src/behavioral-drift.js +801 -801
- package/src/benchmark.js +67 -67
- package/src/catalog.js +103 -103
- package/src/certification.js +128 -128
- package/src/codex/config-parser.js +183 -183
- package/src/codex/context.js +223 -223
- package/src/codex/deep-review.js +493 -493
- package/src/codex/domain-packs.js +394 -394
- package/src/codex/freshness.js +84 -84
- package/src/codex/governance.js +192 -192
- package/src/codex/interactive.js +618 -618
- package/src/codex/mcp-packs.js +914 -914
- package/src/codex/patch.js +209 -209
- package/src/codex/plans.js +251 -251
- package/src/codex/premium.js +614 -614
- package/src/codex/setup.js +591 -591
- package/src/context.js +320 -320
- package/src/continuous-ops.js +681 -681
- package/src/copilot/activity.js +309 -309
- package/src/copilot/deep-review.js +346 -346
- package/src/copilot/domain-packs.js +372 -372
- package/src/copilot/freshness.js +57 -57
- package/src/copilot/governance.js +222 -222
- package/src/copilot/interactive.js +406 -406
- package/src/copilot/mcp-packs.js +826 -826
- package/src/copilot/plans.js +253 -253
- package/src/copilot/premium.js +451 -451
- package/src/copilot/setup.js +488 -488
- package/src/cost-tracking.js +61 -61
- package/src/cursor/activity.js +301 -301
- package/src/cursor/config-parser.js +265 -265
- package/src/cursor/context.js +256 -256
- package/src/cursor/deep-review.js +334 -334
- package/src/cursor/domain-packs.js +368 -368
- package/src/cursor/freshness.js +65 -65
- package/src/cursor/governance.js +229 -229
- package/src/cursor/interactive.js +391 -391
- package/src/cursor/mcp-packs.js +828 -828
- package/src/cursor/plans.js +254 -254
- package/src/cursor/premium.js +469 -469
- package/src/cursor/setup.js +488 -488
- package/src/dashboard.js +493 -493
- package/src/deep-review.js +428 -428
- package/src/deprecation.js +98 -98
- package/src/diff-only.js +280 -280
- package/src/doctor.js +119 -119
- package/src/domain-pack-expansion.js +1033 -1033
- package/src/domain-packs.js +387 -387
- package/src/feedback.js +178 -178
- package/src/fix-engine.js +783 -783
- package/src/fix-prompts.js +122 -122
- package/src/formatters/sarif.js +115 -115
- package/src/freshness.js +74 -74
- package/src/gemini/config-parser.js +275 -275
- package/src/gemini/context.js +221 -221
- package/src/gemini/deep-review.js +559 -559
- package/src/gemini/domain-packs.js +393 -393
- package/src/gemini/freshness.js +66 -66
- package/src/gemini/governance.js +201 -201
- package/src/gemini/interactive.js +860 -860
- package/src/gemini/mcp-packs.js +915 -915
- package/src/gemini/plans.js +269 -269
- package/src/gemini/premium.js +760 -760
- package/src/gemini/setup.js +692 -692
- package/src/gemini/techniques.js +14 -14
- package/src/governance.js +72 -72
- package/src/harmony/add.js +68 -68
- package/src/harmony/advisor.js +333 -333
- package/src/harmony/canon.js +565 -565
- package/src/harmony/cli.js +591 -591
- package/src/harmony/drift.js +401 -401
- package/src/harmony/governance.js +313 -313
- package/src/harmony/memory.js +239 -239
- package/src/harmony/sync.js +475 -475
- package/src/harmony/watch.js +370 -370
- package/src/hook-validation.js +342 -342
- package/src/index.js +271 -271
- package/src/init.js +184 -184
- package/src/instruction-surfaces.js +185 -185
- package/src/integrations.js +144 -144
- package/src/interactive.js +118 -118
- package/src/locales/en.json +1 -1
- package/src/locales/es.json +1 -1
- package/src/mcp-packs.js +830 -830
- package/src/mcp-server.js +726 -726
- package/src/mcp-validation.js +337 -337
- package/src/nerviq-sync.json +7 -7
- package/src/opencode/config-parser.js +109 -109
- package/src/opencode/context.js +247 -247
- package/src/opencode/deep-review.js +313 -313
- package/src/opencode/domain-packs.js +262 -262
- package/src/opencode/freshness.js +66 -66
- package/src/opencode/governance.js +159 -159
- package/src/opencode/interactive.js +392 -392
- package/src/opencode/mcp-packs.js +705 -705
- package/src/opencode/patch.js +184 -184
- package/src/opencode/plans.js +231 -231
- package/src/opencode/premium.js +413 -413
- package/src/opencode/setup.js +449 -449
- package/src/opencode/techniques.js +27 -27
- package/src/operating-profile.js +574 -574
- package/src/org.js +152 -152
- package/src/permission-rules.js +218 -218
- package/src/plans.js +839 -839
- package/src/platform-change-manifest.js +86 -86
- package/src/plugins.js +110 -110
- package/src/policy-layers.js +210 -210
- package/src/profiles.js +124 -124
- package/src/prompt-injection.js +74 -74
- package/src/public-api.js +173 -173
- package/src/recommendation-rules.js +84 -84
- package/src/repo-archetype.js +386 -386
- package/src/secret-patterns.js +39 -39
- package/src/server.js +527 -527
- package/src/setup/analysis.js +607 -607
- package/src/setup/runtime.js +172 -172
- package/src/setup.js +677 -677
- package/src/shared/capabilities.js +194 -194
- package/src/source-urls.js +132 -132
- package/src/stack-checks.js +565 -565
- package/src/supplemental-checks.js +13 -13
- package/src/synergy/adaptive.js +261 -261
- package/src/synergy/compensation.js +137 -137
- package/src/synergy/evidence.js +193 -193
- package/src/synergy/learning.js +199 -199
- package/src/synergy/patterns.js +227 -227
- package/src/synergy/ranking.js +83 -83
- package/src/synergy/report.js +165 -165
- package/src/synergy/routing.js +146 -146
- package/src/techniques/api.js +407 -407
- package/src/techniques/automation.js +316 -316
- package/src/techniques/compliance.js +257 -257
- package/src/techniques/hygiene.js +294 -294
- package/src/techniques/instructions.js +243 -243
- package/src/techniques/observability.js +226 -226
- package/src/techniques/optimization.js +142 -142
- package/src/techniques/quality.js +318 -318
- package/src/techniques/security.js +237 -237
- package/src/techniques/shared.js +443 -443
- package/src/techniques/stacks.js +2294 -2294
- package/src/techniques/tools.js +106 -106
- package/src/techniques/workflow.js +413 -413
- package/src/techniques.js +81 -81
- package/src/terminology.js +73 -73
- package/src/token-estimate.js +35 -35
- package/src/usage-patterns.js +99 -99
- package/src/verification-metadata.js +145 -145
- package/src/watch.js +247 -247
- package/src/windsurf/activity.js +302 -302
- package/src/windsurf/config-parser.js +267 -267
- package/src/windsurf/context.js +249 -249
- package/src/windsurf/deep-review.js +337 -337
- package/src/windsurf/domain-packs.js +370 -370
- package/src/windsurf/freshness.js +36 -36
- package/src/windsurf/governance.js +231 -231
- package/src/windsurf/interactive.js +388 -388
- package/src/windsurf/mcp-packs.js +792 -792
- package/src/windsurf/plans.js +247 -247
- package/src/windsurf/premium.js +468 -468
- package/src/windsurf/setup.js +471 -471
- package/src/windsurf/techniques.js +17 -17
- package/src/workspace.js +375 -375
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Security technique fragments.
|
|
3
|
-
* Generated mechanically from the legacy techniques.js monolith during HR-09.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
collectClaudeDenyRules,
|
|
8
|
-
hasPromptInjectionDefenseGuidance,
|
|
9
|
-
hasMcpPromptInjectionDefenseGuidance,
|
|
10
|
-
hasInjectionDefenseHookConfigured,
|
|
11
|
-
getRepoInstructionBundle,
|
|
12
|
-
getWorkflowContent,
|
|
13
|
-
} = require('./shared');
|
|
14
|
-
|
|
15
|
-
module.exports = {
|
|
16
|
-
settingsPermissions: {
|
|
17
|
-
id: 24,
|
|
18
|
-
name: 'Permission configuration',
|
|
19
|
-
check: (ctx) => {
|
|
20
|
-
// Prefer local (effective config) — any settings file with permissions passes
|
|
21
|
-
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
22
|
-
return !!(settings && settings.permissions);
|
|
23
|
-
},
|
|
24
|
-
impact: 'medium',
|
|
25
|
-
rating: 4,
|
|
26
|
-
category: 'security',
|
|
27
|
-
fix: 'Configure allow/deny permission lists for safe tool usage.',
|
|
28
|
-
template: null
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
permissionDeny: {
|
|
32
|
-
id: 2401,
|
|
33
|
-
name: 'Deny rules configured in permissions',
|
|
34
|
-
check: (ctx) => {
|
|
35
|
-
return collectClaudeDenyRules(ctx).length > 0;
|
|
36
|
-
},
|
|
37
|
-
impact: 'high',
|
|
38
|
-
rating: 5,
|
|
39
|
-
category: 'security',
|
|
40
|
-
fix: 'Add permissions.deny rules to block dangerous operations (e.g. rm -rf, dropping databases).',
|
|
41
|
-
template: null
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
noBypassPermissions: {
|
|
45
|
-
id: 2402,
|
|
46
|
-
name: 'Default mode is not bypassPermissions',
|
|
47
|
-
check: (ctx) => {
|
|
48
|
-
// Check shared settings first (committed to git) — if the shared baseline
|
|
49
|
-
// is safe, a personal settings.local.json override should not fail the audit.
|
|
50
|
-
const shared = ctx.jsonFile('.claude/settings.json');
|
|
51
|
-
if (shared && shared.permissions) {
|
|
52
|
-
return shared.permissions.defaultMode !== 'bypassPermissions';
|
|
53
|
-
}
|
|
54
|
-
const local = ctx.jsonFile('.claude/settings.local.json');
|
|
55
|
-
if (!local || !local.permissions) return null;
|
|
56
|
-
return local.permissions.defaultMode !== 'bypassPermissions';
|
|
57
|
-
},
|
|
58
|
-
impact: 'critical',
|
|
59
|
-
rating: 5,
|
|
60
|
-
category: 'security',
|
|
61
|
-
fix: 'Do not set defaultMode to bypassPermissions. Use explicit allow rules instead.',
|
|
62
|
-
template: null
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
secretsProtection: {
|
|
66
|
-
id: 1096,
|
|
67
|
-
name: 'Secrets protection configured',
|
|
68
|
-
check: (ctx) => {
|
|
69
|
-
const shared = ctx.jsonFile('.claude/settings.json');
|
|
70
|
-
const local = ctx.jsonFile('.claude/settings.local.json');
|
|
71
|
-
const settings = shared || local;
|
|
72
|
-
if (!settings || !settings.permissions) return false;
|
|
73
|
-
const denyRules = collectClaudeDenyRules(ctx);
|
|
74
|
-
const hasDeny = denyRules.some((rule) => rule.protectsSecrets);
|
|
75
|
-
// Fail if allow includes "*" (overly broad — bypasses deny rules)
|
|
76
|
-
const allow = settings.permissions.allow || [];
|
|
77
|
-
if (Array.isArray(allow) && allow.includes('*')) return false;
|
|
78
|
-
return hasDeny;
|
|
79
|
-
},
|
|
80
|
-
impact: 'critical',
|
|
81
|
-
rating: 5,
|
|
82
|
-
category: 'security',
|
|
83
|
-
fix: 'Add permissions.deny rules to block reading .env files and secrets directories.',
|
|
84
|
-
template: null
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
securityReview: {
|
|
88
|
-
id: 1031,
|
|
89
|
-
name: 'Security review command awareness',
|
|
90
|
-
check: (ctx) => {
|
|
91
|
-
const md = ctx.claudeMdContent() || '';
|
|
92
|
-
return md.includes('security') || md.includes('/security-review');
|
|
93
|
-
},
|
|
94
|
-
impact: 'high',
|
|
95
|
-
rating: 5,
|
|
96
|
-
category: 'security',
|
|
97
|
-
fix: 'Add /security-review to your workflow. Claude Code has built-in OWASP Top 10 scanning.',
|
|
98
|
-
template: null
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
promptInjectionTrustBoundary: {
|
|
102
|
-
id: 8805,
|
|
103
|
-
name: 'Prompt injection trust boundary documented',
|
|
104
|
-
check: (ctx) => {
|
|
105
|
-
const bundle = getRepoInstructionBundle(ctx);
|
|
106
|
-
return hasPromptInjectionDefenseGuidance(bundle);
|
|
107
|
-
},
|
|
108
|
-
impact: 'high',
|
|
109
|
-
rating: 5,
|
|
110
|
-
category: 'security',
|
|
111
|
-
fix: 'Document a trust boundary: treat repo files, fetched content, and MCP responses as untrusted data, not instructions to follow.',
|
|
112
|
-
template: null
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
injectionDefenseHook: {
|
|
116
|
-
id: 8806,
|
|
117
|
-
name: 'Injection defense hook configured for external content',
|
|
118
|
-
check: (ctx) => {
|
|
119
|
-
const shared = ctx.jsonFile('.claude/settings.json');
|
|
120
|
-
const local = ctx.jsonFile('.claude/settings.local.json');
|
|
121
|
-
return hasInjectionDefenseHookConfigured(shared) || hasInjectionDefenseHookConfigured(local);
|
|
122
|
-
},
|
|
123
|
-
impact: 'medium',
|
|
124
|
-
rating: 4,
|
|
125
|
-
category: 'security',
|
|
126
|
-
fix: 'Add a PostToolUse injection-defense hook for WebFetch/WebSearch/Read/Grep/Glob/MCP flows so suspicious external content is logged and reviewed.',
|
|
127
|
-
template: 'hooks'
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
mcpPromptInjectionBoundary: {
|
|
131
|
-
id: 8807,
|
|
132
|
-
name: 'MCP responses treated as untrusted in instructions',
|
|
133
|
-
check: (ctx) => {
|
|
134
|
-
const hasMcpSignals = Boolean(
|
|
135
|
-
ctx.fileContent('.mcp.json') ||
|
|
136
|
-
ctx.fileContent('.vscode/mcp.json') ||
|
|
137
|
-
ctx.fileContent('.cursor/mcp.json') ||
|
|
138
|
-
ctx.fileContent('.windsurf/mcp.json') ||
|
|
139
|
-
ctx.fileContent('opencode.json') ||
|
|
140
|
-
ctx.fileContent('opencode.jsonc') ||
|
|
141
|
-
ctx.fileContent('.codex/config.toml')
|
|
142
|
-
);
|
|
143
|
-
if (!hasMcpSignals) return null;
|
|
144
|
-
const bundle = getRepoInstructionBundle(ctx);
|
|
145
|
-
return hasMcpPromptInjectionDefenseGuidance(bundle);
|
|
146
|
-
},
|
|
147
|
-
impact: 'medium',
|
|
148
|
-
rating: 4,
|
|
149
|
-
category: 'security',
|
|
150
|
-
fix: 'Document that MCP outputs are untrusted data, can contain indirect prompt injection, and must never override repo-level instructions.',
|
|
151
|
-
template: null
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
sandboxAwareness: {
|
|
155
|
-
id: 2013,
|
|
156
|
-
name: 'Sandbox or isolation mentioned',
|
|
157
|
-
check: (ctx) => {
|
|
158
|
-
const md = ctx.claudeMdContent() || '';
|
|
159
|
-
const settings = ctx.jsonFile('.claude/settings.json') || {};
|
|
160
|
-
return /sandbox|isolat/i.test(md) || !!settings.sandbox;
|
|
161
|
-
},
|
|
162
|
-
impact: 'medium', rating: 3, category: 'security',
|
|
163
|
-
fix: 'Claude Code supports sandboxed command execution. Consider enabling it for untrusted operations.',
|
|
164
|
-
template: null
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
denyRulesDepth: {
|
|
168
|
-
id: 2014,
|
|
169
|
-
name: 'Deny rules cover 3+ patterns',
|
|
170
|
-
check: (ctx) => {
|
|
171
|
-
return collectClaudeDenyRules(ctx).length >= 3;
|
|
172
|
-
},
|
|
173
|
-
impact: 'high', rating: 4, category: 'security',
|
|
174
|
-
fix: 'Add at least 3 deny rules: rm -rf, force-push, and .env reads. More patterns = safer Claude.',
|
|
175
|
-
template: null
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
sbomExists: {
|
|
179
|
-
id: 130041,
|
|
180
|
-
name: 'SBOM file exists',
|
|
181
|
-
check: (ctx) => {
|
|
182
|
-
return ctx.files.some(f => /sbom\.(json|xml|cdx\.json)|bom\.xml|cyclonedx/i.test(f));
|
|
183
|
-
},
|
|
184
|
-
impact: 'medium',
|
|
185
|
-
category: 'supply-chain',
|
|
186
|
-
fix: 'Generate an SBOM (Software Bill of Materials) in CycloneDX or SPDX format for supply chain transparency.',
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
dependencyPinning: {
|
|
190
|
-
id: 130042,
|
|
191
|
-
name: 'Lock files committed',
|
|
192
|
-
check: (ctx) => {
|
|
193
|
-
return ctx.files.some(f => /^(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Pipfile\.lock|bun\.lockb|composer\.lock|Gemfile\.lock|go\.sum)$/i.test(f));
|
|
194
|
-
},
|
|
195
|
-
impact: 'high',
|
|
196
|
-
category: 'supply-chain',
|
|
197
|
-
fix: 'Commit lock files (package-lock.json, yarn.lock, Cargo.lock, poetry.lock) for reproducible builds.',
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
provenanceAttestation: {
|
|
201
|
-
id: 130043,
|
|
202
|
-
name: 'Provenance or sigstore in CI',
|
|
203
|
-
check: (ctx) => {
|
|
204
|
-
const ci = getWorkflowContent(ctx);
|
|
205
|
-
return /provenance|sigstore|cosign|slsa|attestation/i.test(ci);
|
|
206
|
-
},
|
|
207
|
-
impact: 'medium',
|
|
208
|
-
category: 'supply-chain',
|
|
209
|
-
fix: 'Add npm provenance or sigstore attestation in CI to verify package integrity.',
|
|
210
|
-
},
|
|
211
|
-
|
|
212
|
-
lockfileIntegrity: {
|
|
213
|
-
id: 130044,
|
|
214
|
-
name: 'CI uses frozen lockfile install',
|
|
215
|
-
check: (ctx) => {
|
|
216
|
-
const ci = getWorkflowContent(ctx);
|
|
217
|
-
return /npm ci\b|--frozen-lockfile|--immutable|cargo.*--locked|pip install.*--require-hashes/i.test(ci);
|
|
218
|
-
},
|
|
219
|
-
impact: 'high',
|
|
220
|
-
category: 'supply-chain',
|
|
221
|
-
fix: 'Use `npm ci` or `--frozen-lockfile` in CI instead of `npm install` for deterministic builds.',
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
dependencyScanning: {
|
|
225
|
-
id: 130045,
|
|
226
|
-
name: 'Dependency scanning configured',
|
|
227
|
-
check: (ctx) => {
|
|
228
|
-
const hasConfig = ctx.files.some(f => /dependabot\.yml|renovate\.json|\.snyk/i.test(f));
|
|
229
|
-
if (hasConfig) return true;
|
|
230
|
-
const ci = getWorkflowContent(ctx);
|
|
231
|
-
return /dependabot|renovate|snyk|npm audit|cargo audit|pip-audit|safety check/i.test(ci);
|
|
232
|
-
},
|
|
233
|
-
impact: 'high',
|
|
234
|
-
category: 'supply-chain',
|
|
235
|
-
fix: 'Configure Dependabot, Renovate, or Snyk to automatically scan and update vulnerable dependencies.',
|
|
236
|
-
},
|
|
237
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Security technique fragments.
|
|
3
|
+
* Generated mechanically from the legacy techniques.js monolith during HR-09.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
collectClaudeDenyRules,
|
|
8
|
+
hasPromptInjectionDefenseGuidance,
|
|
9
|
+
hasMcpPromptInjectionDefenseGuidance,
|
|
10
|
+
hasInjectionDefenseHookConfigured,
|
|
11
|
+
getRepoInstructionBundle,
|
|
12
|
+
getWorkflowContent,
|
|
13
|
+
} = require('./shared');
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
settingsPermissions: {
|
|
17
|
+
id: 24,
|
|
18
|
+
name: 'Permission configuration',
|
|
19
|
+
check: (ctx) => {
|
|
20
|
+
// Prefer local (effective config) — any settings file with permissions passes
|
|
21
|
+
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
22
|
+
return !!(settings && settings.permissions);
|
|
23
|
+
},
|
|
24
|
+
impact: 'medium',
|
|
25
|
+
rating: 4,
|
|
26
|
+
category: 'security',
|
|
27
|
+
fix: 'Configure allow/deny permission lists for safe tool usage.',
|
|
28
|
+
template: null
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
permissionDeny: {
|
|
32
|
+
id: 2401,
|
|
33
|
+
name: 'Deny rules configured in permissions',
|
|
34
|
+
check: (ctx) => {
|
|
35
|
+
return collectClaudeDenyRules(ctx).length > 0;
|
|
36
|
+
},
|
|
37
|
+
impact: 'high',
|
|
38
|
+
rating: 5,
|
|
39
|
+
category: 'security',
|
|
40
|
+
fix: 'Add permissions.deny rules to block dangerous operations (e.g. rm -rf, dropping databases).',
|
|
41
|
+
template: null
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
noBypassPermissions: {
|
|
45
|
+
id: 2402,
|
|
46
|
+
name: 'Default mode is not bypassPermissions',
|
|
47
|
+
check: (ctx) => {
|
|
48
|
+
// Check shared settings first (committed to git) — if the shared baseline
|
|
49
|
+
// is safe, a personal settings.local.json override should not fail the audit.
|
|
50
|
+
const shared = ctx.jsonFile('.claude/settings.json');
|
|
51
|
+
if (shared && shared.permissions) {
|
|
52
|
+
return shared.permissions.defaultMode !== 'bypassPermissions';
|
|
53
|
+
}
|
|
54
|
+
const local = ctx.jsonFile('.claude/settings.local.json');
|
|
55
|
+
if (!local || !local.permissions) return null;
|
|
56
|
+
return local.permissions.defaultMode !== 'bypassPermissions';
|
|
57
|
+
},
|
|
58
|
+
impact: 'critical',
|
|
59
|
+
rating: 5,
|
|
60
|
+
category: 'security',
|
|
61
|
+
fix: 'Do not set defaultMode to bypassPermissions. Use explicit allow rules instead.',
|
|
62
|
+
template: null
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
secretsProtection: {
|
|
66
|
+
id: 1096,
|
|
67
|
+
name: 'Secrets protection configured',
|
|
68
|
+
check: (ctx) => {
|
|
69
|
+
const shared = ctx.jsonFile('.claude/settings.json');
|
|
70
|
+
const local = ctx.jsonFile('.claude/settings.local.json');
|
|
71
|
+
const settings = shared || local;
|
|
72
|
+
if (!settings || !settings.permissions) return false;
|
|
73
|
+
const denyRules = collectClaudeDenyRules(ctx);
|
|
74
|
+
const hasDeny = denyRules.some((rule) => rule.protectsSecrets);
|
|
75
|
+
// Fail if allow includes "*" (overly broad — bypasses deny rules)
|
|
76
|
+
const allow = settings.permissions.allow || [];
|
|
77
|
+
if (Array.isArray(allow) && allow.includes('*')) return false;
|
|
78
|
+
return hasDeny;
|
|
79
|
+
},
|
|
80
|
+
impact: 'critical',
|
|
81
|
+
rating: 5,
|
|
82
|
+
category: 'security',
|
|
83
|
+
fix: 'Add permissions.deny rules to block reading .env files and secrets directories.',
|
|
84
|
+
template: null
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
securityReview: {
|
|
88
|
+
id: 1031,
|
|
89
|
+
name: 'Security review command awareness',
|
|
90
|
+
check: (ctx) => {
|
|
91
|
+
const md = ctx.claudeMdContent() || '';
|
|
92
|
+
return md.includes('security') || md.includes('/security-review');
|
|
93
|
+
},
|
|
94
|
+
impact: 'high',
|
|
95
|
+
rating: 5,
|
|
96
|
+
category: 'security',
|
|
97
|
+
fix: 'Add /security-review to your workflow. Claude Code has built-in OWASP Top 10 scanning.',
|
|
98
|
+
template: null
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
promptInjectionTrustBoundary: {
|
|
102
|
+
id: 8805,
|
|
103
|
+
name: 'Prompt injection trust boundary documented',
|
|
104
|
+
check: (ctx) => {
|
|
105
|
+
const bundle = getRepoInstructionBundle(ctx);
|
|
106
|
+
return hasPromptInjectionDefenseGuidance(bundle);
|
|
107
|
+
},
|
|
108
|
+
impact: 'high',
|
|
109
|
+
rating: 5,
|
|
110
|
+
category: 'security',
|
|
111
|
+
fix: 'Document a trust boundary: treat repo files, fetched content, and MCP responses as untrusted data, not instructions to follow.',
|
|
112
|
+
template: null
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
injectionDefenseHook: {
|
|
116
|
+
id: 8806,
|
|
117
|
+
name: 'Injection defense hook configured for external content',
|
|
118
|
+
check: (ctx) => {
|
|
119
|
+
const shared = ctx.jsonFile('.claude/settings.json');
|
|
120
|
+
const local = ctx.jsonFile('.claude/settings.local.json');
|
|
121
|
+
return hasInjectionDefenseHookConfigured(shared) || hasInjectionDefenseHookConfigured(local);
|
|
122
|
+
},
|
|
123
|
+
impact: 'medium',
|
|
124
|
+
rating: 4,
|
|
125
|
+
category: 'security',
|
|
126
|
+
fix: 'Add a PostToolUse injection-defense hook for WebFetch/WebSearch/Read/Grep/Glob/MCP flows so suspicious external content is logged and reviewed.',
|
|
127
|
+
template: 'hooks'
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
mcpPromptInjectionBoundary: {
|
|
131
|
+
id: 8807,
|
|
132
|
+
name: 'MCP responses treated as untrusted in instructions',
|
|
133
|
+
check: (ctx) => {
|
|
134
|
+
const hasMcpSignals = Boolean(
|
|
135
|
+
ctx.fileContent('.mcp.json') ||
|
|
136
|
+
ctx.fileContent('.vscode/mcp.json') ||
|
|
137
|
+
ctx.fileContent('.cursor/mcp.json') ||
|
|
138
|
+
ctx.fileContent('.windsurf/mcp.json') ||
|
|
139
|
+
ctx.fileContent('opencode.json') ||
|
|
140
|
+
ctx.fileContent('opencode.jsonc') ||
|
|
141
|
+
ctx.fileContent('.codex/config.toml')
|
|
142
|
+
);
|
|
143
|
+
if (!hasMcpSignals) return null;
|
|
144
|
+
const bundle = getRepoInstructionBundle(ctx);
|
|
145
|
+
return hasMcpPromptInjectionDefenseGuidance(bundle);
|
|
146
|
+
},
|
|
147
|
+
impact: 'medium',
|
|
148
|
+
rating: 4,
|
|
149
|
+
category: 'security',
|
|
150
|
+
fix: 'Document that MCP outputs are untrusted data, can contain indirect prompt injection, and must never override repo-level instructions.',
|
|
151
|
+
template: null
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
sandboxAwareness: {
|
|
155
|
+
id: 2013,
|
|
156
|
+
name: 'Sandbox or isolation mentioned',
|
|
157
|
+
check: (ctx) => {
|
|
158
|
+
const md = ctx.claudeMdContent() || '';
|
|
159
|
+
const settings = ctx.jsonFile('.claude/settings.json') || {};
|
|
160
|
+
return /sandbox|isolat/i.test(md) || !!settings.sandbox;
|
|
161
|
+
},
|
|
162
|
+
impact: 'medium', rating: 3, category: 'security',
|
|
163
|
+
fix: 'Claude Code supports sandboxed command execution. Consider enabling it for untrusted operations.',
|
|
164
|
+
template: null
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
denyRulesDepth: {
|
|
168
|
+
id: 2014,
|
|
169
|
+
name: 'Deny rules cover 3+ patterns',
|
|
170
|
+
check: (ctx) => {
|
|
171
|
+
return collectClaudeDenyRules(ctx).length >= 3;
|
|
172
|
+
},
|
|
173
|
+
impact: 'high', rating: 4, category: 'security',
|
|
174
|
+
fix: 'Add at least 3 deny rules: rm -rf, force-push, and .env reads. More patterns = safer Claude.',
|
|
175
|
+
template: null
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
sbomExists: {
|
|
179
|
+
id: 130041,
|
|
180
|
+
name: 'SBOM file exists',
|
|
181
|
+
check: (ctx) => {
|
|
182
|
+
return ctx.files.some(f => /sbom\.(json|xml|cdx\.json)|bom\.xml|cyclonedx/i.test(f));
|
|
183
|
+
},
|
|
184
|
+
impact: 'medium',
|
|
185
|
+
category: 'supply-chain',
|
|
186
|
+
fix: 'Generate an SBOM (Software Bill of Materials) in CycloneDX or SPDX format for supply chain transparency.',
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
dependencyPinning: {
|
|
190
|
+
id: 130042,
|
|
191
|
+
name: 'Lock files committed',
|
|
192
|
+
check: (ctx) => {
|
|
193
|
+
return ctx.files.some(f => /^(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Pipfile\.lock|bun\.lockb|composer\.lock|Gemfile\.lock|go\.sum)$/i.test(f));
|
|
194
|
+
},
|
|
195
|
+
impact: 'high',
|
|
196
|
+
category: 'supply-chain',
|
|
197
|
+
fix: 'Commit lock files (package-lock.json, yarn.lock, Cargo.lock, poetry.lock) for reproducible builds.',
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
provenanceAttestation: {
|
|
201
|
+
id: 130043,
|
|
202
|
+
name: 'Provenance or sigstore in CI',
|
|
203
|
+
check: (ctx) => {
|
|
204
|
+
const ci = getWorkflowContent(ctx);
|
|
205
|
+
return /provenance|sigstore|cosign|slsa|attestation/i.test(ci);
|
|
206
|
+
},
|
|
207
|
+
impact: 'medium',
|
|
208
|
+
category: 'supply-chain',
|
|
209
|
+
fix: 'Add npm provenance or sigstore attestation in CI to verify package integrity.',
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
lockfileIntegrity: {
|
|
213
|
+
id: 130044,
|
|
214
|
+
name: 'CI uses frozen lockfile install',
|
|
215
|
+
check: (ctx) => {
|
|
216
|
+
const ci = getWorkflowContent(ctx);
|
|
217
|
+
return /npm ci\b|--frozen-lockfile|--immutable|cargo.*--locked|pip install.*--require-hashes/i.test(ci);
|
|
218
|
+
},
|
|
219
|
+
impact: 'high',
|
|
220
|
+
category: 'supply-chain',
|
|
221
|
+
fix: 'Use `npm ci` or `--frozen-lockfile` in CI instead of `npm install` for deterministic builds.',
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
dependencyScanning: {
|
|
225
|
+
id: 130045,
|
|
226
|
+
name: 'Dependency scanning configured',
|
|
227
|
+
check: (ctx) => {
|
|
228
|
+
const hasConfig = ctx.files.some(f => /dependabot\.yml|renovate\.json|\.snyk/i.test(f));
|
|
229
|
+
if (hasConfig) return true;
|
|
230
|
+
const ci = getWorkflowContent(ctx);
|
|
231
|
+
return /dependabot|renovate|snyk|npm audit|cargo audit|pip-audit|safety check/i.test(ci);
|
|
232
|
+
},
|
|
233
|
+
impact: 'high',
|
|
234
|
+
category: 'supply-chain',
|
|
235
|
+
fix: 'Configure Dependabot, Renovate, or Snyk to automatically scan and update vulnerable dependencies.',
|
|
236
|
+
},
|
|
237
|
+
};
|