praxis-sec 1.0.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 +21 -0
- package/README.md +170 -0
- package/ai-defense/cost-protection.md +292 -0
- package/ai-defense/llm-security-checklist.md +324 -0
- package/ai-defense/prompt-injection-patterns.js +283 -0
- package/ai-defense/system-prompt-armor.md +327 -0
- package/checklists/launch-day.md +168 -0
- package/cli/agents/abom-generator.js +225 -0
- package/cli/agents/agent-attestation-agent.js +318 -0
- package/cli/agents/agent-config-scanner.js +787 -0
- package/cli/agents/agent-telemetry-agent.js +415 -0
- package/cli/agents/agentic-security-agent.js +296 -0
- package/cli/agents/agentic-supply-chain-agent.js +463 -0
- package/cli/agents/ai-infra-inventory-agent.js +449 -0
- package/cli/agents/api-fuzzer.js +345 -0
- package/cli/agents/auth-bypass-agent.js +348 -0
- package/cli/agents/base-agent.js +280 -0
- package/cli/agents/cicd-scanner.js +300 -0
- package/cli/agents/config-auditor.js +757 -0
- package/cli/agents/deep-analyzer.js +776 -0
- package/cli/agents/endpoint-agent-abuse-agent.js +404 -0
- package/cli/agents/exception-handler-agent.js +187 -0
- package/cli/agents/git-history-scanner.js +169 -0
- package/cli/agents/governance-audits.js +138 -0
- package/cli/agents/hermes-security-agent.js +536 -0
- package/cli/agents/html-reporter.js +1125 -0
- package/cli/agents/index.js +147 -0
- package/cli/agents/injection-tester.js +502 -0
- package/cli/agents/legal-risk-agent.js +328 -0
- package/cli/agents/llm-redteam.js +199 -0
- package/cli/agents/managed-agent-scanner.js +333 -0
- package/cli/agents/mcp-security-agent.js +588 -0
- package/cli/agents/memory-poisoning-agent.js +305 -0
- package/cli/agents/mobile-scanner.js +231 -0
- package/cli/agents/model-file-scanner.js +259 -0
- package/cli/agents/orchestrator.js +355 -0
- package/cli/agents/pii-compliance-agent.js +301 -0
- package/cli/agents/policy-engine.js +229 -0
- package/cli/agents/prompt-injection-prober.js +224 -0
- package/cli/agents/rag-security-agent.js +204 -0
- package/cli/agents/recon-agent.js +207 -0
- package/cli/agents/sbom-generator.js +265 -0
- package/cli/agents/scoring-engine.js +273 -0
- package/cli/agents/ssrf-prober.js +130 -0
- package/cli/agents/stateful-watcher.js +238 -0
- package/cli/agents/supabase-rls-agent.js +154 -0
- package/cli/agents/supply-chain-agent.js +857 -0
- package/cli/agents/swarm-orchestrator.js +200 -0
- package/cli/agents/verifier-agent.js +303 -0
- package/cli/agents/vibe-coding-agent.js +250 -0
- package/cli/bin/praxis.js +866 -0
- package/cli/commands/abom.js +73 -0
- package/cli/commands/agent-fix.js +1245 -0
- package/cli/commands/audit.js +1180 -0
- package/cli/commands/autofix.js +383 -0
- package/cli/commands/baseline.js +193 -0
- package/cli/commands/benchmark.js +327 -0
- package/cli/commands/checklist.js +223 -0
- package/cli/commands/ci.js +403 -0
- package/cli/commands/deps.js +516 -0
- package/cli/commands/diff.js +200 -0
- package/cli/commands/doctor.js +195 -0
- package/cli/commands/env-audit.js +349 -0
- package/cli/commands/fix.js +218 -0
- package/cli/commands/guard.js +396 -0
- package/cli/commands/hooks.js +278 -0
- package/cli/commands/init.js +514 -0
- package/cli/commands/legal.js +158 -0
- package/cli/commands/live-advisories.js +241 -0
- package/cli/commands/mcp.js +660 -0
- package/cli/commands/openclaw.js +386 -0
- package/cli/commands/red-team.js +350 -0
- package/cli/commands/redteam.js +78 -0
- package/cli/commands/remediate.js +797 -0
- package/cli/commands/rotate.js +768 -0
- package/cli/commands/rules.js +196 -0
- package/cli/commands/scan-mcp.js +534 -0
- package/cli/commands/scan-skill.js +588 -0
- package/cli/commands/scan-standard.js +251 -0
- package/cli/commands/scan.js +524 -0
- package/cli/commands/score.js +449 -0
- package/cli/commands/shell.js +514 -0
- package/cli/commands/team-report.js +398 -0
- package/cli/commands/undo.js +161 -0
- package/cli/commands/update-intel.js +126 -0
- package/cli/commands/vibe-check.js +276 -0
- package/cli/commands/watch.js +757 -0
- package/cli/commands/web.js +63 -0
- package/cli/core/ast/guardrail-detector.js +141 -0
- package/cli/core/ast/index.js +22 -0
- package/cli/core/ast/parser.js +676 -0
- package/cli/core/ast/scope-tree.js +287 -0
- package/cli/core/ast/taint-tracker.js +158 -0
- package/cli/core/branding.js +37 -0
- package/cli/core/env.js +38 -0
- package/cli/core/errors.js +61 -0
- package/cli/core/fs.js +62 -0
- package/cli/core/output/compliance.js +90 -0
- package/cli/core/output/html-theme.js +158 -0
- package/cli/core/output/index.js +57 -0
- package/cli/core/output/json.js +48 -0
- package/cli/core/output/sarif.js +240 -0
- package/cli/core/version.js +67 -0
- package/cli/core/web/jobs.js +183 -0
- package/cli/core/web/projects.js +146 -0
- package/cli/core/web/server.js +439 -0
- package/cli/data/atlas-knowledge.json +5640 -0
- package/cli/data/eaa-catalog.json +39 -0
- package/cli/data/known-mcps.json +26 -0
- package/cli/data/probes/prompt-injection-corpus.json +271 -0
- package/cli/data/threat-intel.json +85 -0
- package/cli/data/threatpacks/latest.json +41 -0
- package/cli/hooks/patterns.js +313 -0
- package/cli/hooks/post-tool-use.js +140 -0
- package/cli/hooks/pre-tool-use.js +186 -0
- package/cli/index.js +90 -0
- package/cli/providers/llm-provider.js +766 -0
- package/cli/utils/autofix-rules.js +74 -0
- package/cli/utils/cache-manager.js +310 -0
- package/cli/utils/compliance-map.js +191 -0
- package/cli/utils/entropy.js +132 -0
- package/cli/utils/fix-ledger.js +127 -0
- package/cli/utils/hermes-tool-registry.js +252 -0
- package/cli/utils/intel/cache.js +61 -0
- package/cli/utils/intel/http.js +88 -0
- package/cli/utils/intel/index.js +235 -0
- package/cli/utils/intel/merge.js +229 -0
- package/cli/utils/intel/sources/epss.js +54 -0
- package/cli/utils/intel/sources/ghsa.js +81 -0
- package/cli/utils/intel/sources/gitguardian.js +40 -0
- package/cli/utils/intel/sources/gitleaks.js +101 -0
- package/cli/utils/intel/sources/kev.js +38 -0
- package/cli/utils/intel/sources/nvd.js +84 -0
- package/cli/utils/intel/sources/osv.js +132 -0
- package/cli/utils/intel/sources/phylum.js +44 -0
- package/cli/utils/intel/sources/snyk.js +46 -0
- package/cli/utils/intel/sources/socket.js +69 -0
- package/cli/utils/intel/sources/sonatype.js +84 -0
- package/cli/utils/intel/sources/threatpack.js +69 -0
- package/cli/utils/mcp-trust.js +60 -0
- package/cli/utils/output.js +251 -0
- package/cli/utils/patterns.js +1130 -0
- package/cli/utils/pdf-generator.js +94 -0
- package/cli/utils/plugin-loader.js +364 -0
- package/cli/utils/rule-import.js +228 -0
- package/cli/utils/rule-registry.js +426 -0
- package/cli/utils/scan-fingerprint.js +109 -0
- package/cli/utils/scan-playbook.js +312 -0
- package/cli/utils/score-history.js +119 -0
- package/cli/utils/secrets-verifier.js +247 -0
- package/cli/utils/security-memory.js +296 -0
- package/cli/utils/standards/atlas-knowledge.js +87 -0
- package/cli/utils/standards/index.js +127 -0
- package/cli/utils/standards/sources/avid.js +45 -0
- package/cli/utils/standards/sources/eu-ai-act.js +89 -0
- package/cli/utils/standards/sources/google-saif.js +39 -0
- package/cli/utils/standards/sources/iso-42001.js +94 -0
- package/cli/utils/standards/sources/mitre-atlas.js +54 -0
- package/cli/utils/standards/sources/nist-ai-600-1.js +45 -0
- package/cli/utils/standards/sources/owasp-llm.js +45 -0
- package/cli/utils/standards/sources/owasp-ml.js +45 -0
- package/cli/utils/threat-intel.js +265 -0
- package/configs/firebase/firestore-rules.txt +215 -0
- package/configs/firebase/security-checklist.md +236 -0
- package/configs/firebase/storage-rules.txt +206 -0
- package/configs/gitignore-template +258 -0
- package/configs/nextjs-security-headers.js +220 -0
- package/configs/praxisignore-template +50 -0
- package/configs/supabase/secure-client.ts +225 -0
- package/configs/supabase/security-checklist.md +278 -0
- package/docs/THIRD_PARTY_NOTICES.md +26 -0
- package/docs/THREAT_INTEL.md +292 -0
- package/docs/USAGE.md +1205 -0
- package/docs/design/WEB-UI.md +82 -0
- package/package.json +71 -0
- package/scripts/check-determinism.mjs +119 -0
- package/snippets/README.md +122 -0
- package/snippets/api-security/api-security-checklist.md +412 -0
- package/snippets/api-security/cors-config.ts +322 -0
- package/snippets/api-security/input-validation.ts +430 -0
- package/snippets/auth/jwt-checklist.md +322 -0
- package/snippets/rate-limiting/nextjs-middleware.ts +211 -0
- package/snippets/rate-limiting/upstash-ratelimit.ts +229 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan Standard Command
|
|
3
|
+
* =====================
|
|
4
|
+
*
|
|
5
|
+
* Runs a normal scan and filters the result to findings tagged with a
|
|
6
|
+
* specific AI-security standard (OWASP LLM, MITRE ATLAS, NIST AI 600-1, etc.).
|
|
7
|
+
*
|
|
8
|
+
* USAGE:
|
|
9
|
+
* praxis scan standard --list # list available standards
|
|
10
|
+
* praxis scan standard owasp-llm . # findings tagged with the OWASP LLM Top 10
|
|
11
|
+
* praxis scan standard mitre-atlas . --json # ATLAS findings as JSON
|
|
12
|
+
* praxis scan standard owasp-llm . --control LLM01 # filter to a single control
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import chalk from 'chalk';
|
|
18
|
+
import ora from 'ora';
|
|
19
|
+
import { buildOrchestratorAsync } from '../agents/index.js';
|
|
20
|
+
import { ScoringEngine } from '../agents/scoring-engine.js';
|
|
21
|
+
import {
|
|
22
|
+
ALL_STANDARDS,
|
|
23
|
+
listStandards,
|
|
24
|
+
getStandard,
|
|
25
|
+
filterFindingsByStandard,
|
|
26
|
+
} from '../utils/standards/index.js';
|
|
27
|
+
import { render, hasFormat } from '../core/output/index.js';
|
|
28
|
+
|
|
29
|
+
const SEV_COLORS = {
|
|
30
|
+
critical: chalk.red.bold,
|
|
31
|
+
high: chalk.red,
|
|
32
|
+
medium: chalk.yellow,
|
|
33
|
+
low: chalk.blue,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export async function scanStandardCommand(name, targetPath = '.', options = {}) {
|
|
37
|
+
if (options.list || name === 'list') {
|
|
38
|
+
return printStandardsList(options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!name) {
|
|
42
|
+
console.error(chalk.red(' Missing standard name.'));
|
|
43
|
+
console.error(chalk.gray(' Usage: praxis scan standard <name> [path]'));
|
|
44
|
+
console.error(chalk.gray(' praxis scan standard --list'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const standard = getStandard(name);
|
|
49
|
+
if (!standard) {
|
|
50
|
+
console.error(chalk.red(` Unknown standard: ${name}`));
|
|
51
|
+
console.error(chalk.gray(' Available:'));
|
|
52
|
+
for (const s of listStandards()) {
|
|
53
|
+
console.error(chalk.gray(` ${s.name.padEnd(16)} ${s.title}`));
|
|
54
|
+
}
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const absolutePath = path.resolve(targetPath);
|
|
59
|
+
if (!fs.existsSync(absolutePath)) {
|
|
60
|
+
console.error(chalk.red(` Path does not exist: ${absolutePath}`));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const machine = !!(options.json || options.sarif);
|
|
65
|
+
|
|
66
|
+
if (!machine) {
|
|
67
|
+
console.log();
|
|
68
|
+
console.log(chalk.cyan.bold(` Praxis — ${standard.title} (${standard.version})`));
|
|
69
|
+
console.log(chalk.gray(` ${standard.description}`));
|
|
70
|
+
console.log(chalk.gray(` ${standard.url}`));
|
|
71
|
+
console.log();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const spinner = machine ? null : ora({ text: 'Running agents...', color: 'cyan' }).start();
|
|
75
|
+
const orchestrator = await buildOrchestratorAsync(absolutePath, { quiet: true });
|
|
76
|
+
const result = await orchestrator.runAll(absolutePath, { quiet: true });
|
|
77
|
+
if (spinner) spinner.succeed(chalk.green(`Scanned ${result.findings.length} finding(s) total`));
|
|
78
|
+
|
|
79
|
+
const scoring = new ScoringEngine();
|
|
80
|
+
const scoreResult = scoring.compute(result.findings);
|
|
81
|
+
|
|
82
|
+
const filtered = filterFindingsByStandard(
|
|
83
|
+
result.findings,
|
|
84
|
+
standard.name,
|
|
85
|
+
options.control || null
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const standardSummary = buildStandardSummary(standard, filtered, options.control);
|
|
89
|
+
|
|
90
|
+
const report = {
|
|
91
|
+
standard: {
|
|
92
|
+
name: standard.name,
|
|
93
|
+
version: standard.version,
|
|
94
|
+
title: standard.title,
|
|
95
|
+
url: standard.url,
|
|
96
|
+
},
|
|
97
|
+
control: options.control || null,
|
|
98
|
+
totalFindings: filtered.length,
|
|
99
|
+
coverage: standardSummary.coverage,
|
|
100
|
+
flaggedControls: standardSummary.flaggedControls,
|
|
101
|
+
totalControls: standardSummary.totalControls,
|
|
102
|
+
controls: standardSummary.controls,
|
|
103
|
+
findings: filtered.map(f => ({
|
|
104
|
+
...f,
|
|
105
|
+
file: String(f.file || '')
|
|
106
|
+
.replace(/\\/g, '/')
|
|
107
|
+
.replace(/^[a-zA-Z]:\/+/, '')
|
|
108
|
+
.replace(/^.*\/Praxis\/showcase-target\//, 'showcase-target/')
|
|
109
|
+
.replace(/^.*\/Praxis\//, ''),
|
|
110
|
+
})),
|
|
111
|
+
score: scoreResult.score,
|
|
112
|
+
grade: scoreResult.grade?.letter || 'A',
|
|
113
|
+
scannedAt: new Date().toISOString(),
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// ATLAS enrichment: hydrate flagged techniques with mitigations + case studies
|
|
117
|
+
if (standard.name === 'mitre-atlas') {
|
|
118
|
+
try {
|
|
119
|
+
const { getTechniqueDetails, atlasSnapshot } = await import('../utils/standards/sources/mitre-atlas.js');
|
|
120
|
+
report.atlas = {
|
|
121
|
+
snapshot: atlasSnapshot(),
|
|
122
|
+
techniques: Object.fromEntries(
|
|
123
|
+
standardSummary.controls
|
|
124
|
+
.filter(c => c.findingCount > 0)
|
|
125
|
+
.map(c => [c.id, getTechniqueDetails(c.id)])
|
|
126
|
+
.filter(([, d]) => d)
|
|
127
|
+
),
|
|
128
|
+
};
|
|
129
|
+
} catch { /* enrichment is best-effort */ }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (options.json) {
|
|
133
|
+
console.log(render('json', report));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (options.sarif) {
|
|
137
|
+
console.log(render('sarif', report));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (options.format && hasFormat(options.format)) {
|
|
141
|
+
console.log(render(options.format, report));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await printHumanReport(standard, report, options);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function buildStandardSummary(standard, findings, controlFilter) {
|
|
149
|
+
const counts = {};
|
|
150
|
+
for (const f of findings) {
|
|
151
|
+
const ids = (f.standards || {})[standard.name] || [];
|
|
152
|
+
for (const id of ids) {
|
|
153
|
+
if (controlFilter && id !== controlFilter) continue;
|
|
154
|
+
counts[id] = (counts[id] || 0) + 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const controls = (standard.controls || [])
|
|
158
|
+
.filter(c => !controlFilter || c.id === controlFilter)
|
|
159
|
+
.map(c => ({
|
|
160
|
+
...c,
|
|
161
|
+
findingCount: counts[c.id] || 0,
|
|
162
|
+
status: counts[c.id] ? 'flagged' : 'clear',
|
|
163
|
+
}));
|
|
164
|
+
const flaggedControls = controls.filter(c => c.findingCount > 0).length;
|
|
165
|
+
return {
|
|
166
|
+
totalControls: controls.length,
|
|
167
|
+
flaggedControls,
|
|
168
|
+
coverage: `${flaggedControls}/${controls.length}`,
|
|
169
|
+
controls,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function printStandardsList(options) {
|
|
174
|
+
if (options.json) {
|
|
175
|
+
console.log(JSON.stringify(listStandards(), null, 2));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
console.log();
|
|
179
|
+
console.log(chalk.cyan.bold(' Available AI-security standards'));
|
|
180
|
+
console.log();
|
|
181
|
+
for (const s of listStandards()) {
|
|
182
|
+
console.log(` ${chalk.white.bold(s.name.padEnd(16))} ${chalk.gray(`v${s.version}`).padEnd(12)} ${s.title}`);
|
|
183
|
+
console.log(chalk.gray(` ${s.controlCount} controls — ${s.url}`));
|
|
184
|
+
}
|
|
185
|
+
console.log();
|
|
186
|
+
console.log(chalk.gray(` Total: ${ALL_STANDARDS.length} standards.`));
|
|
187
|
+
console.log();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function printHumanReport(standard, report) { console.log(chalk.white.bold(` Coverage: ${report.coverage} (${report.totalFindings} finding${report.totalFindings === 1 ? '' : 's'})`));
|
|
191
|
+
console.log();
|
|
192
|
+
|
|
193
|
+
for (const ctrl of report.controls) {
|
|
194
|
+
const statusIcon = ctrl.findingCount > 0 ? chalk.red('●') : chalk.green('○');
|
|
195
|
+
const head = ctrl.findingCount > 0
|
|
196
|
+
? chalk.white.bold(`${ctrl.id} — ${ctrl.title}`) + chalk.yellow(` (${ctrl.findingCount})`)
|
|
197
|
+
: chalk.gray(`${ctrl.id} — ${ctrl.title}`);
|
|
198
|
+
console.log(` ${statusIcon} ${head}`);
|
|
199
|
+
}
|
|
200
|
+
console.log();
|
|
201
|
+
|
|
202
|
+
// ATLAS enrichment: mitigations + case studies for flagged techniques
|
|
203
|
+
if (standard.name === 'mitre-atlas') {
|
|
204
|
+
try {
|
|
205
|
+
const { getTechniqueDetails, atlasSnapshot } = await import('../utils/standards/sources/mitre-atlas.js');
|
|
206
|
+
const flagged = report.controls.filter(c => c.findingCount > 0);
|
|
207
|
+
if (flagged.length > 0) {
|
|
208
|
+
console.log(chalk.gray(` ATLAS knowledge snapshot: ${atlasSnapshot()}`));
|
|
209
|
+
console.log(chalk.white.bold(' Recommended mitigations (ATLAS):'));
|
|
210
|
+
console.log();
|
|
211
|
+
const shown = new Set();
|
|
212
|
+
for (const ctrl of flagged) {
|
|
213
|
+
const details = getTechniqueDetails(ctrl.id);
|
|
214
|
+
if (!details) continue;
|
|
215
|
+
for (const m of details.mitigations) {
|
|
216
|
+
if (shown.has(m.id)) continue;
|
|
217
|
+
shown.add(m.id);
|
|
218
|
+
console.log(` ${chalk.cyan(m.id)} ${m.name}`);
|
|
219
|
+
}
|
|
220
|
+
if (details.caseStudies.length > 0) {
|
|
221
|
+
console.log(chalk.gray(` case studies: ${details.caseStudies.map(cs => cs.name).join('; ')}`));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
console.log();
|
|
225
|
+
}
|
|
226
|
+
} catch { /* enrichment is best-effort */ }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (report.totalFindings === 0) {
|
|
230
|
+
console.log(chalk.green(` ✔ No findings tagged with ${standard.title}.`));
|
|
231
|
+
console.log();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log(chalk.white.bold(' Findings:'));
|
|
236
|
+
console.log();
|
|
237
|
+
for (const f of report.findings.slice(0, 50)) {
|
|
238
|
+
const ids = (f.standards || {})[standard.name] || [];
|
|
239
|
+
const sev = (f.severity || 'medium').toUpperCase();
|
|
240
|
+
const color = SEV_COLORS[f.severity] || chalk.white;
|
|
241
|
+
const tag = ids.join(', ');
|
|
242
|
+
const file = f.file ? path.relative(process.cwd(), f.file) : '';
|
|
243
|
+
const loc = file ? `${file}:${f.line || 0}` : '';
|
|
244
|
+
console.log(` ${color(`[${sev}]`)} ${chalk.cyan(`[${tag}]`)} ${f.title || f.rule || ''}`);
|
|
245
|
+
if (loc) console.log(chalk.gray(` ${loc}`));
|
|
246
|
+
}
|
|
247
|
+
if (report.findings.length > 50) {
|
|
248
|
+
console.log(chalk.gray(` …and ${report.findings.length - 50} more (use --json for the full list).`));
|
|
249
|
+
}
|
|
250
|
+
console.log();
|
|
251
|
+
}
|