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,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `praxis rules` — inspect and export Praxis's detection rules.
|
|
3
|
+
*
|
|
4
|
+
* Two subcommands:
|
|
5
|
+
* list summarise the rule inventory by source, severity and portability
|
|
6
|
+
* export write a Semgrep-compatible bundle plus an honest manifest
|
|
7
|
+
*
|
|
8
|
+
* The manifest is the important half. A bundle without it would imply Praxis is
|
|
9
|
+
* nothing but its patterns; the manifest names the layers that have no Semgrep
|
|
10
|
+
* equivalent (AST/taint, the probe corpus, entropy heuristics). See
|
|
11
|
+
* docs/ and P-IMP-059 in the improvement plan.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import { collectPortableRules, dedupeRules, writeBundle, SEMGREP_SEVERITY } from '../utils/rule-registry.js';
|
|
17
|
+
import { loadPortableBundle, writePlugin } from '../utils/rule-import.js';
|
|
18
|
+
import { toolVersion } from '../core/version.js';
|
|
19
|
+
import * as output from '../utils/output.js';
|
|
20
|
+
|
|
21
|
+
async function gather() {
|
|
22
|
+
const collected = await collectPortableRules();
|
|
23
|
+
const { rules, collisions } = dedupeRules(collected.rules);
|
|
24
|
+
return { ...collected, rules, collisions };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function rulesListCommand(options = {}) {
|
|
28
|
+
const { rules, errors, skipped, collisions } = await gather();
|
|
29
|
+
|
|
30
|
+
const bySeverity = {};
|
|
31
|
+
for (const r of rules) bySeverity[r.severity] = (bySeverity[r.severity] || 0) + 1;
|
|
32
|
+
|
|
33
|
+
const byOrigin = {};
|
|
34
|
+
for (const r of rules) {
|
|
35
|
+
const src = r.origin.split(':')[0];
|
|
36
|
+
byOrigin[src] = (byOrigin[src] || 0) + 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (options.json) {
|
|
40
|
+
console.log(JSON.stringify({
|
|
41
|
+
total: rules.length,
|
|
42
|
+
bySeverity,
|
|
43
|
+
bySource: byOrigin,
|
|
44
|
+
portable: rules.filter(r => r.valid).length,
|
|
45
|
+
invalid: rules.filter(r => !r.valid).length,
|
|
46
|
+
collisions,
|
|
47
|
+
skipped,
|
|
48
|
+
moduleErrors: errors,
|
|
49
|
+
}, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
output.header('Praxis rule inventory');
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(` ${chalk.green(String(rules.length))} exportable pattern rules`);
|
|
56
|
+
console.log(` ${chalk.gray(`${rules.filter(r => r.valid).length} validated · ${rules.filter(r => !r.valid).length} invalid · ${collisions.length} id collision(s)`)}`);
|
|
57
|
+
console.log();
|
|
58
|
+
|
|
59
|
+
console.log(chalk.gray(' By severity:'));
|
|
60
|
+
for (const [sev, n] of Object.entries(bySeverity).sort((a, b) => b[1] - a[1])) {
|
|
61
|
+
console.log(` ${String(n).padStart(4)} ${sev.padEnd(9)} semgrep: ${SEMGREP_SEVERITY[sev] || 'WARNING'}`);
|
|
62
|
+
}
|
|
63
|
+
console.log();
|
|
64
|
+
|
|
65
|
+
console.log(chalk.gray(' By source (top 12):'));
|
|
66
|
+
for (const [src, n] of Object.entries(byOrigin).sort((a, b) => b[1] - a[1]).slice(0, 12)) {
|
|
67
|
+
console.log(` ${String(n).padStart(4)} ${src}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (errors.length) {
|
|
71
|
+
console.log();
|
|
72
|
+
console.log(chalk.yellow(` ${errors.length} module(s) could not be loaded:`));
|
|
73
|
+
for (const e of errors) console.log(` ${e.module}: ${e.error}`);
|
|
74
|
+
}
|
|
75
|
+
if (skipped.length) {
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk.gray(` ${skipped.length} record(s) had no regex and were skipped.`));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(chalk.gray(' Praxis-only layers (no Semgrep equivalent): AST/taint dataflow,'));
|
|
82
|
+
console.log(chalk.gray(' the prompt-injection probe corpus, entropy-checked secrets, LLM deep analysis.'));
|
|
83
|
+
console.log(chalk.gray(' Run `praxis rules export` for the full manifest.'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function rulesExportCommand(options = {}) {
|
|
87
|
+
const outDir = path.resolve(options.out || 'praxis-rules');
|
|
88
|
+
const { rules, collisions, errors, skipped } = await gather();
|
|
89
|
+
|
|
90
|
+
if (rules.length === 0) {
|
|
91
|
+
output.error('No exportable rules found — refusing to write an empty bundle.');
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const invalid = rules.filter(r => r.validationStatus === 'invalid');
|
|
97
|
+
const unverifiable = rules.filter(r => r.validationStatus === 'unverifiable');
|
|
98
|
+
|
|
99
|
+
// Refuse to ship a bundle containing patterns that do not compile. A partially
|
|
100
|
+
// broken bundle would fail inside someone else's Semgrep with no useful context.
|
|
101
|
+
if (invalid.length > 0 && !options.allowInvalid) {
|
|
102
|
+
output.error(`${invalid.length} pattern(s) failed validation — refusing to write a broken bundle.`);
|
|
103
|
+
for (const r of invalid.slice(0, 5)) console.log(` ${r.id}: ${r.validationError}`);
|
|
104
|
+
console.log(chalk.gray(' Fix them, or re-run with --allow-invalid to export anyway.'));
|
|
105
|
+
process.exitCode = 1;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { yamlPath, jsonPath, manifestPath } = writeBundle({
|
|
110
|
+
rules,
|
|
111
|
+
collisions,
|
|
112
|
+
errors,
|
|
113
|
+
skipped,
|
|
114
|
+
outDir,
|
|
115
|
+
toolVersion: toolVersion(),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
output.success(`Exported ${rules.length - invalid.length} portable rule(s)`);
|
|
119
|
+
console.log(` ${yamlPath} (Semgrep)`);
|
|
120
|
+
console.log(` ${jsonPath} (canonical, re-importable)`);
|
|
121
|
+
console.log(` ${manifestPath}`);
|
|
122
|
+
if (unverifiable.length) {
|
|
123
|
+
console.log(chalk.yellow(` (${unverifiable.length} pattern(s) could not be machine-checked — valid PCRE2 with no JS equivalent; listed in the manifest)`));
|
|
124
|
+
}
|
|
125
|
+
if (invalid.length) console.log(chalk.yellow(` (${invalid.length} invalid pattern(s) included via --allow-invalid)`));
|
|
126
|
+
if (collisions.length) console.log(chalk.yellow(` (${collisions.length} duplicate rule id(s) suffixed; see the manifest)`));
|
|
127
|
+
if (errors.length) console.log(chalk.yellow(` (${errors.length} module(s) failed to load; see the manifest)`));
|
|
128
|
+
console.log();
|
|
129
|
+
console.log(chalk.gray(' Use with Semgrep: semgrep --config ' + yamlPath + ' <target>'));
|
|
130
|
+
console.log(chalk.gray(' Re-import with Praxis: praxis rules import ' + jsonPath));
|
|
131
|
+
console.log(chalk.gray(' praxis-rules.manifest.json lists what Praxis does that Semgrep cannot.'));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function rulesImportCommand(bundleFile, options = {}) {
|
|
135
|
+
const loaded = loadPortableBundle(bundleFile);
|
|
136
|
+
|
|
137
|
+
if (!loaded.ok) {
|
|
138
|
+
output.error(loaded.error);
|
|
139
|
+
process.exitCode = 1;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const { accepted, rejected, meta } = loaded;
|
|
144
|
+
|
|
145
|
+
if (options.json) {
|
|
146
|
+
console.log(JSON.stringify({
|
|
147
|
+
source: meta.source,
|
|
148
|
+
total: meta.total,
|
|
149
|
+
accepted: accepted.length,
|
|
150
|
+
rejected: rejected.length,
|
|
151
|
+
rejections: rejected,
|
|
152
|
+
praxisOnlyLayers: meta.praxisOnlyLayers,
|
|
153
|
+
}, null, 2));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
output.header('Portable rule import');
|
|
158
|
+
console.log();
|
|
159
|
+
console.log(` bundle: ${meta.source}`);
|
|
160
|
+
if (meta.praxisVersion) console.log(chalk.gray(` produced by Praxis ${meta.praxisVersion}`));
|
|
161
|
+
console.log();
|
|
162
|
+
console.log(` ${chalk.green(String(accepted.length))} accepted · ${chalk.yellow(String(rejected.length))} rejected`);
|
|
163
|
+
console.log();
|
|
164
|
+
|
|
165
|
+
if (rejected.length) {
|
|
166
|
+
console.log(chalk.gray(' Rejected (with reasons — nothing is imported in degraded form):'));
|
|
167
|
+
const byReason = {};
|
|
168
|
+
for (const r of rejected) byReason[r.reason] = (byReason[r.reason] || 0) + 1;
|
|
169
|
+
for (const [reason, n] of Object.entries(byReason).sort((a, b) => b[1] - a[1])) {
|
|
170
|
+
console.log(` ${String(n).padStart(4)} ${reason}`);
|
|
171
|
+
}
|
|
172
|
+
console.log();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (meta.praxisOnlyLayers?.length) {
|
|
176
|
+
console.log(chalk.gray(' Declared Praxis-only layers in this bundle (cannot be imported as patterns):'));
|
|
177
|
+
for (const l of meta.praxisOnlyLayers) console.log(` - ${l.layer}: ${l.reason}`);
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (accepted.length === 0) {
|
|
182
|
+
output.error('No importable pattern rules in this bundle.');
|
|
183
|
+
process.exitCode = 1;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (options.writePlugin) {
|
|
188
|
+
const dir = path.resolve(options.writePlugin);
|
|
189
|
+
const file = writePlugin(accepted, dir, { name: options.name || 'PortableRules' });
|
|
190
|
+
output.success(`Wrote ${accepted.length} rule(s) to ${file}`);
|
|
191
|
+
console.log(chalk.gray(' It runs automatically in every `praxis audit` from this directory down.'));
|
|
192
|
+
} else {
|
|
193
|
+
console.log(chalk.gray(' Preview only. Re-run with --write-plugin <dir> to emit a runnable plugin.'));
|
|
194
|
+
console.log(chalk.gray(` e.g. --write-plugin ${path.join('.praxis', 'agents')}`));
|
|
195
|
+
}
|
|
196
|
+
}
|