praxis-sec 1.2.1 → 1.2.4

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.
Files changed (53) hide show
  1. package/README.md +84 -115
  2. package/ai-defense/cost-protection.md +6 -0
  3. package/ai-defense/llm-security-checklist.md +6 -0
  4. package/ai-defense/system-prompt-armor.md +7 -1
  5. package/assets/praxis-architecture.svg +304 -0
  6. package/assets/praxis-logo.svg +38 -0
  7. package/checklists/launch-day.md +6 -7
  8. package/cli/agents/agent-telemetry-agent.js +2 -0
  9. package/cli/agents/api-fuzzer.js +2 -2
  10. package/cli/agents/git-history-scanner.js +14 -15
  11. package/cli/agents/html-reporter.js +9 -8
  12. package/cli/agents/mcp-security-agent.js +600 -594
  13. package/cli/agents/memory-poisoning-agent.js +1 -5
  14. package/cli/agents/orchestrator.js +375 -360
  15. package/cli/commands/agent-fix.js +3 -1
  16. package/cli/commands/audit.js +1272 -1228
  17. package/cli/commands/autofix.js +32 -13
  18. package/cli/commands/baseline.js +4 -2
  19. package/cli/commands/benchmark.js +2 -1
  20. package/cli/commands/ci.js +12 -8
  21. package/cli/commands/diff.js +2 -1
  22. package/cli/commands/env-audit.js +4 -2
  23. package/cli/commands/fix.js +2 -1
  24. package/cli/commands/legal.js +2 -1
  25. package/cli/commands/mcp.js +54 -51
  26. package/cli/commands/openclaw.js +3 -6
  27. package/cli/commands/red-team.js +2 -1
  28. package/cli/commands/remediate.js +2 -1
  29. package/cli/commands/rotate.js +2 -1
  30. package/cli/commands/scan-mcp.js +20 -9
  31. package/cli/commands/scan-standard.js +3 -6
  32. package/cli/commands/scan.js +15 -7
  33. package/cli/commands/score.js +2 -1
  34. package/cli/commands/vibe-check.js +4 -2
  35. package/cli/commands/watch.js +8 -6
  36. package/cli/core/glob.js +7 -5
  37. package/cli/core/output/json.js +56 -48
  38. package/cli/core/paths.js +91 -0
  39. package/cli/core/web/jobs.js +2 -0
  40. package/cli/data/documented-secret-examples.json +14 -0
  41. package/cli/utils/cache-manager.js +2 -1
  42. package/cli/utils/entropy.js +19 -0
  43. package/cli/utils/hermes-tool-registry.js +11 -9
  44. package/configs/firebase/security-checklist.md +3 -3
  45. package/configs/supabase/security-checklist.md +19 -21
  46. package/docs/RELEASE-1.2.4.md +85 -0
  47. package/docs/RELEASING.md +51 -0
  48. package/docs/THIRD_PARTY_NOTICES.md +8 -0
  49. package/docs/THREAT_INTEL.md +4 -2
  50. package/docs/USAGE.md +97 -76
  51. package/package.json +6 -4
  52. package/snippets/README.md +6 -0
  53. package/snippets/auth/jwt-checklist.md +14 -13
@@ -0,0 +1,304 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="960" height="1340" viewBox="0 0 960 1340" role="img" aria-label="Praxis AI Security Architecture and Autonomous Fix Loop Flow">
2
+ <defs>
3
+ <!-- Background Canvas Gradient -->
4
+ <linearGradient id="bgGrad" x1="0" y1="0" x2="0" y2="1">
5
+ <stop offset="0%" stop-color="#120726"/>
6
+ <stop offset="40%" stop-color="#090314"/>
7
+ <stop offset="100%" stop-color="#030108"/>
8
+ </linearGradient>
9
+
10
+ <!-- Ambient Top Purple Glow -->
11
+ <radialGradient id="topGlow" cx="50%" cy="0%" r="50%">
12
+ <stop offset="0%" stop-color="#8b5cf6" stop-opacity="0.32"/>
13
+ <stop offset="100%" stop-color="#8b5cf6" stop-opacity="0"/>
14
+ </radialGradient>
15
+
16
+ <!-- Card Backgrounds -->
17
+ <linearGradient id="cardScan" x1="0" y1="0" x2="1" y2="0">
18
+ <stop offset="0%" stop-color="#1f0e38"/>
19
+ <stop offset="100%" stop-color="#130824"/>
20
+ </linearGradient>
21
+
22
+ <linearGradient id="cardNorm" x1="0" y1="0" x2="1" y2="0">
23
+ <stop offset="0%" stop-color="#241042"/>
24
+ <stop offset="100%" stop-color="#140926"/>
25
+ </linearGradient>
26
+
27
+ <linearGradient id="cardLlm" x1="0" y1="0" x2="1" y2="0">
28
+ <stop offset="0%" stop-color="#2a0d4a"/>
29
+ <stop offset="100%" stop-color="#18072c"/>
30
+ </linearGradient>
31
+
32
+ <linearGradient id="cardVerify" x1="0" y1="0" x2="1" y2="0">
33
+ <stop offset="0%" stop-color="#0e2a22"/>
34
+ <stop offset="100%" stop-color="#081813"/>
35
+ </linearGradient>
36
+
37
+ <linearGradient id="cardHitl" x1="0" y1="0" x2="1" y2="0">
38
+ <stop offset="0%" stop-color="#241403"/>
39
+ <stop offset="100%" stop-color="#140a02"/>
40
+ </linearGradient>
41
+
42
+ <linearGradient id="cardSurfaces" x1="0" y1="0" x2="1" y2="0">
43
+ <stop offset="0%" stop-color="#082f49"/>
44
+ <stop offset="100%" stop-color="#04141f"/>
45
+ </linearGradient>
46
+
47
+ <!-- Brand Color Gradients -->
48
+ <linearGradient id="praxisGrad" x1="0" y1="0" x2="1" y2="0">
49
+ <stop offset="0%" stop-color="#c084fc"/>
50
+ <stop offset="50%" stop-color="#8b5cf6"/>
51
+ <stop offset="100%" stop-color="#6d28d9"/>
52
+ </linearGradient>
53
+
54
+ <linearGradient id="emeraldGrad" x1="0" y1="0" x2="1" y2="0">
55
+ <stop offset="0%" stop-color="#6ee7b7"/>
56
+ <stop offset="100%" stop-color="#10b981"/>
57
+ </linearGradient>
58
+
59
+ <linearGradient id="goldGrad" x1="0" y1="0" x2="1" y2="0">
60
+ <stop offset="0%" stop-color="#fde047"/>
61
+ <stop offset="100%" stop-color="#f59e0b"/>
62
+ </linearGradient>
63
+
64
+ <linearGradient id="cyanGrad" x1="0" y1="0" x2="1" y2="0">
65
+ <stop offset="0%" stop-color="#38bdf8"/>
66
+ <stop offset="100%" stop-color="#0284c7"/>
67
+ </linearGradient>
68
+
69
+ <!-- Glowing Filters -->
70
+ <filter id="shadow" x="-10%" y="-10%" width="120%" height="120%">
71
+ <feDropShadow dx="0" dy="6" stdDeviation="6" flood-color="#000000" flood-opacity="0.8"/>
72
+ </filter>
73
+ <filter id="glowPurple" x="-20%" y="-20%" width="140%" height="140%">
74
+ <feDropShadow dx="0" dy="0" stdDeviation="6" flood-color="#c084fc" flood-opacity="0.5"/>
75
+ </filter>
76
+ <filter id="glowGreen" x="-20%" y="-20%" width="140%" height="140%">
77
+ <feDropShadow dx="0" dy="0" stdDeviation="6" flood-color="#10b981" flood-opacity="0.5"/>
78
+ </filter>
79
+
80
+ <!-- Arrow Markers -->
81
+ <marker id="arrDownPurple" markerWidth="10" markerHeight="10" refX="5" refY="7" orient="auto">
82
+ <polygon points="0 0, 10 0, 5 8" fill="#c084fc"/>
83
+ </marker>
84
+ <marker id="arrDownCyan" markerWidth="10" markerHeight="10" refX="5" refY="7" orient="auto">
85
+ <polygon points="0 0, 10 0, 5 8" fill="#38bdf8"/>
86
+ </marker>
87
+ <marker id="arrDownGreen" markerWidth="10" markerHeight="10" refX="5" refY="7" orient="auto">
88
+ <polygon points="0 0, 10 0, 5 8" fill="#34d399"/>
89
+ </marker>
90
+ <marker id="arrDownGold" markerWidth="10" markerHeight="10" refX="5" refY="7" orient="auto">
91
+ <polygon points="0 0, 10 0, 5 8" fill="#f59e0b"/>
92
+ </marker>
93
+ </defs>
94
+
95
+ <!-- Base Canvas Background -->
96
+ <rect width="960" height="1340" fill="url(#bgGrad)"/>
97
+ <rect width="960" height="420" fill="url(#topGlow)"/>
98
+
99
+ <!-- ========================================================================= -->
100
+ <!-- HEADER &amp; LOGO -->
101
+ <!-- ========================================================================= -->
102
+ <g transform="translate(480, 48)">
103
+ <!-- Shield Logo Icon -->
104
+ <g transform="translate(-295, -26) scale(0.38)">
105
+ <path d="M55 0 L110 18 V62 C110 100 86 128 55 145 C24 128 0 100 0 62 V18 Z" fill="url(#praxisGrad)" stroke="#4c1d95" stroke-width="3"/>
106
+ <path d="M55 24 L82 40 V66 C82 92 68 110 55 120 C42 110 28 92 28 66 V40 Z" fill="#ffffff" opacity="0.95"/>
107
+ </g>
108
+ <text x="24" y="8" text-anchor="middle" font-family="'Segoe UI', -apple-system, sans-serif" font-size="32" font-weight="900" letter-spacing="0.5">
109
+ <tspan fill="url(#praxisGrad)">PRAXIS</tspan>
110
+ <tspan fill="#ffffff" font-weight="800"> | ARCHITECTURE FLOW</tspan>
111
+ </text>
112
+ <text x="0" y="38" text-anchor="middle" font-family="'Segoe UI', -apple-system, sans-serif" font-size="15" font-weight="600" fill="#e9d5ff">
113
+ 28-Agent Parallel Audit · AST Taint · Remote Git Scanning · 4-Tier Verification · Autonomous Fix
114
+ </text>
115
+ </g>
116
+
117
+ <!-- ========================================================================= -->
118
+ <!-- STEP 1: 28-AGENT CONCURRENT STATIC &amp; AST AUDIT (y=110, h=155) -->
119
+ <!-- ========================================================================= -->
120
+ <g transform="translate(90, 110)" filter="url(#shadow)">
121
+ <rect x="0" y="0" width="780" height="155" rx="14" fill="url(#cardScan)" stroke="#7c3aed" stroke-width="2" filter="url(#glowPurple)"/>
122
+
123
+ <!-- Stage Header Badge -->
124
+ <circle cx="28" cy="28" r="16" fill="#7c3aed"/>
125
+ <text x="28" y="34" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="900" fill="#ffffff">1</text>
126
+
127
+ <text x="56" y="34" font-family="sans-serif" font-size="18.5" font-weight="900" fill="#ffffff">28-AGENT PARALLEL AUDIT &amp; AST TAINT CORE</text>
128
+ <rect x="635" y="14" width="130" height="28" rx="6" fill="#2e1065" stroke="#a855f7" stroke-width="1.2"/>
129
+ <text x="700" y="32" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="800" fill="#c084fc">DETERMINISTIC</text>
130
+
131
+ <!-- Sub-bullets -->
132
+ <g transform="translate(24, 60)">
133
+ <text x="0" y="16" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#f3e8ff">• <tspan font-weight="700">28 Concurrent Agents:</tspan> Prompt Injection · MCP Abuse · Memory Poisoning · RAG · Pickles · Auth</text>
134
+ <text x="0" y="42" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#f3e8ff">• <tspan font-weight="700">AST &amp; Taint Engine:</tspan> Pure ESM Babel (JS/TS) &amp; Python CST with ScopeTree &amp; Source-to-Sink Taint</text>
135
+ <text x="0" y="68" font-family="sans-serif" font-size="14.5" font-weight="700" fill="#34d399">• <tspan font-weight="700">100% Offline &amp; Free:</tspan> 0 token cost, 125 secret &amp; code patterns, 7 cached Threat Intel feeds</text>
136
+ </g>
137
+ </g>
138
+
139
+ <!-- Connector 1 -> 2 -->
140
+ <g transform="translate(480, 265)">
141
+ <line x1="0" y1="0" x2="0" y2="35" stroke="#c084fc" stroke-width="3.5" marker-end="url(#arrDownPurple)"/>
142
+ <rect x="-140" y="8" width="280" height="22" rx="4" fill="#241042" stroke="#7c3aed" stroke-width="1"/>
143
+ <text x="0" y="24" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="800" fill="#e9d5ff">Raw Findings &amp; AST Taint Graphs</text>
144
+ </g>
145
+
146
+ <!-- ========================================================================= -->
147
+ <!-- STEP 2: ACCURACY, STANDARDS &amp; ABOM MATRIX (y=305, h=145) -->
148
+ <!-- ========================================================================= -->
149
+ <g transform="translate(90, 305)" filter="url(#shadow)">
150
+ <rect x="0" y="0" width="780" height="145" rx="14" fill="url(#cardNorm)" stroke="#9333ea" stroke-width="2"/>
151
+
152
+ <!-- Stage Header Badge -->
153
+ <circle cx="28" cy="28" r="16" fill="#9333ea"/>
154
+ <text x="28" y="34" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="900" fill="#ffffff">2</text>
155
+
156
+ <text x="56" y="34" font-family="sans-serif" font-size="18.5" font-weight="900" fill="#ffffff">8-FRAMEWORK STANDARDS MAPPING &amp; ABOM</text>
157
+ <rect x="635" y="14" width="130" height="28" rx="6" fill="#3b0764" stroke="#c084fc" stroke-width="1.2"/>
158
+ <text x="700" y="32" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="800" fill="#e9d5ff">COMPLIANCE</text>
159
+
160
+ <!-- Sub-bullets -->
161
+ <g transform="translate(24, 60)">
162
+ <text x="0" y="16" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#f3e8ff">• <tspan font-weight="700">8 Security Standards:</tspan> OWASP LLM 2025 · MITRE ATLAS · NIST AI 600-1 · EU AI Act (Art 12/14) · ISO 42001</text>
163
+ <text x="0" y="42" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#f3e8ff">• <tspan font-weight="700">CycloneDX 1.5 ABOM:</tspan> Full Agent Bill of Materials (Prompts, Tools, Models, Skills &amp; MCP Trust)</text>
164
+ <text x="0" y="68" font-family="sans-serif" font-size="14.5" font-weight="700" fill="#38bdf8">• <tspan font-weight="700">Scoring Engine:</tspan> Computes 0–100 Health Score &amp; Letter Grade (A–F) with Category Deductions</text>
165
+ </g>
166
+ </g>
167
+
168
+ <!-- Connector 2 -> 3 -->
169
+ <g transform="translate(480, 450)">
170
+ <line x1="0" y1="0" x2="0" y2="35" stroke="#38bdf8" stroke-width="3.5" marker-end="url(#arrDownCyan)"/>
171
+ <rect x="-140" y="8" width="280" height="22" rx="4" fill="#082230" stroke="#0284c7" stroke-width="1"/>
172
+ <text x="0" y="24" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="800" fill="#38bdf8">Deep Analysis / `praxis fix` Trigger</text>
173
+ </g>
174
+
175
+ <!-- ========================================================================= -->
176
+ <!-- STEP 3: COGNITIVE LLM REASONING &amp; REMEDIATION (y=490, h=155) -->
177
+ <!-- ========================================================================= -->
178
+ <g transform="translate(90, 490)" filter="url(#shadow)">
179
+ <rect x="0" y="0" width="780" height="155" rx="14" fill="url(#cardLlm)" stroke="#c084fc" stroke-width="2.2" filter="url(#glowPurple)"/>
180
+
181
+ <!-- Stage Header Badge -->
182
+ <circle cx="28" cy="28" r="16" fill="url(#praxisGrad)"/>
183
+ <text x="28" y="34" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="900" fill="#ffffff">3</text>
184
+
185
+ <text x="56" y="34" font-family="sans-serif" font-size="18.5" font-weight="900" fill="#ffffff">COGNITIVE LLM REASONING &amp; PATCH DRAFTING</text>
186
+ <rect x="635" y="14" width="130" height="28" rx="6" fill="#3b0764" stroke="#c084fc" stroke-width="1.2"/>
187
+ <text x="700" y="32" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="900" fill="#e9d5ff">AGENTIC AI</text>
188
+
189
+ <!-- Sub-bullets -->
190
+ <g transform="translate(24, 60)">
191
+ <text x="0" y="16" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#f3e8ff">• <tspan font-weight="700">Multi-LLM Router:</tspan> Anthropic Claude · OpenAI · DeepSeek · Google Gemini · Local Ollama (`--local`)</text>
192
+ <text x="0" y="42" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#f3e8ff">• <tspan font-weight="700">Exploitability Triage:</tspan> Evaluates call-site reachability &amp; attack vectors to eliminate false alarms</text>
193
+ <text x="0" y="68" font-family="sans-serif" font-size="14.5" font-weight="700" fill="#34d399">• <tspan font-weight="700">Autonomous Code Fix:</tspan> Drafts contextual, multi-file code patches &amp; unit regression tests</text>
194
+ </g>
195
+ </g>
196
+
197
+ <!-- Connector 3 -> 4 -->
198
+ <g transform="translate(480, 645)">
199
+ <line x1="0" y1="0" x2="0" y2="35" stroke="#34d399" stroke-width="3.5" marker-end="url(#arrDownGreen)"/>
200
+ <rect x="-145" y="8" width="290" height="22" rx="4" fill="#09281a" stroke="#10b981" stroke-width="1"/>
201
+ <text x="0" y="24" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="800" fill="#34d399">Draft Diffs to Verification Oracles</text>
202
+ </g>
203
+
204
+ <!-- ========================================================================= -->
205
+ <!-- STEP 4: 4-TIER EXECUTABLE VERIFICATION LADDER (y=685, h=165) -->
206
+ <!-- ========================================================================= -->
207
+ <g transform="translate(90, 685)" filter="url(#shadow)">
208
+ <rect x="0" y="0" width="780" height="165" rx="14" fill="url(#cardVerify)" stroke="#10b981" stroke-width="2.2" filter="url(#glowGreen)"/>
209
+
210
+ <!-- Stage Header Badge -->
211
+ <circle cx="28" cy="28" r="16" fill="url(#emeraldGrad)"/>
212
+ <text x="28" y="34" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="900" fill="#042316">4</text>
213
+
214
+ <text x="56" y="34" font-family="sans-serif" font-size="18.5" font-weight="900" fill="#ffffff">4-TIER EXECUTABLE VERIFICATION LADDER</text>
215
+ <rect x="635" y="14" width="130" height="28" rx="6" fill="#0c2b1e" stroke="#10b981" stroke-width="1.2"/>
216
+ <text x="700" y="32" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="900" fill="#34d399">ORACLES</text>
217
+
218
+ <!-- Sub-bullets -->
219
+ <g transform="translate(24, 60)">
220
+ <text x="0" y="16" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#a7f3d0">• <tspan font-weight="700">Tier 1 (AST Syntax Oracle):</tspan> Validates AST node integrity before any file is touched</text>
221
+ <text x="0" y="42" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#a7f3d0">• <tspan font-weight="700">Tier 2 (Build Oracle):</tspan> Executes project build (`npm run build` / `tsc`) to ensure 0 compiler errors</text>
222
+ <text x="0" y="68" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#a7f3d0">• <tspan font-weight="700">Tier 3 (Test Suite Oracle):</tspan> Runs unit test suite to guarantee zero functionality regressions</text>
223
+ <text x="0" y="92" font-family="sans-serif" font-size="14.5" font-weight="800" fill="#34d399">• <tspan font-weight="700">Tier 4 (Re-scan Oracle):</tspan> Confirms finding resolution — <tspan font-weight="700">Auto-reverts on any oracle failure</tspan></text>
224
+ </g>
225
+ </g>
226
+
227
+ <!-- Connector 4 -> 5 -->
228
+ <g transform="translate(480, 850)">
229
+ <line x1="0" y1="0" x2="0" y2="35" stroke="#f59e0b" stroke-width="3.5" marker-end="url(#arrDownGold)"/>
230
+ <rect x="-140" y="8" width="280" height="22" rx="4" fill="#241403" stroke="#f59e0b" stroke-width="1"/>
231
+ <text x="0" y="24" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="800" fill="#fde047">Verified Diffs to Operator Review</text>
232
+ </g>
233
+
234
+ <!-- ========================================================================= -->
235
+ <!-- STEP 5: HITL APPROVAL &amp; ATOMIC APPLY (y=890, h=165) -->
236
+ <!-- ========================================================================= -->
237
+ <g transform="translate(90, 890)" filter="url(#shadow)">
238
+ <rect x="0" y="0" width="780" height="165" rx="14" fill="url(#cardHitl)" stroke="#f59e0b" stroke-width="2.2"/>
239
+
240
+ <!-- Stage Header Badge -->
241
+ <circle cx="28" cy="28" r="16" fill="url(#goldGrad)"/>
242
+ <text x="28" y="34" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="900" fill="#0c0701">5</text>
243
+
244
+ <text x="56" y="34" font-family="sans-serif" font-size="18.5" font-weight="900" fill="#ffffff">HUMAN APPROVAL, ATOMIC APPLY &amp; REPORT SUITE</text>
245
+ <rect x="635" y="14" width="130" height="28" rx="6" fill="#382006" stroke="#f59e0b" stroke-width="1.2"/>
246
+ <text x="700" y="32" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="900" fill="#fde047">HUMAN-IN-LOOP</text>
247
+
248
+ <!-- Sub-bullets -->
249
+ <g transform="translate(24, 60)">
250
+ <text x="0" y="16" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#fef08a">• <tspan font-weight="700">Interactive Diff Review:</tspan> Developer inspects verified patch before any disk write</text>
251
+ <text x="0" y="42" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#fef08a">• <tspan font-weight="700">Atomic Apply:</tspan> boundary + symlink checks, all-or-nothing rollback, hash-based `praxis undo`</text>
252
+ <text x="0" y="68" font-family="sans-serif" font-size="14.5" font-weight="700" fill="#38bdf8">• <tspan font-weight="700">Assessment Report:</tspan> single-file tabbed HTML — agent coverage, AST taint, ledger, trend</text>
253
+ <text x="0" y="92" font-family="sans-serif" font-size="14.5" font-weight="700" fill="#34d399">• CI/CD Native: Net-new PR gating, SARIF export to GitHub Code Scanning &amp; PR annotations</text>
254
+ </g>
255
+ </g>
256
+
257
+ <!-- ========================================================================= -->
258
+ <!-- LEFT RETURN CONDUIT (Closed Autopilot Loop: Step 5 -> Step 1) -->
259
+ <!-- ========================================================================= -->
260
+ <path d="M 90 975 L 35 975 L 35 185 L 85 185" fill="none" stroke="#8b5cf6" stroke-width="3.5" stroke-dasharray="10 5"/>
261
+ <polygon points="85,185 70,175 70,195" fill="#c084fc"/>
262
+
263
+ <!-- Vertical Feedback Tag -->
264
+ <g transform="translate(25, 580) rotate(-90)">
265
+ <rect x="-160" y="-12" width="320" height="24" rx="4" fill="#1f0e38" stroke="#8b5cf6" stroke-width="1.2"/>
266
+ <text x="0" y="4" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="800" fill="#e9d5ff" letter-spacing="0.5">
267
+ ↻ AUTONOMOUS FIX → VERIFY LOOP
268
+ </text>
269
+ </g>
270
+
271
+ <!-- ========================================================================= -->
272
+ <!-- STAGE 6 : OUTPUT SURFACES, PORTABILITY & REPRODUCIBILITY -->
273
+ <!-- ========================================================================= -->
274
+ <path d="M 480 1055 L 480 1087" fill="none" stroke="#38bdf8" stroke-width="3.5" marker-end="url(#arrDownCyan)"/>
275
+
276
+ <g transform="translate(90, 1095)" filter="url(#shadow)">
277
+ <rect x="0" y="0" width="780" height="165" rx="14" fill="url(#cardSurfaces)" stroke="#38bdf8" stroke-width="2.2"/>
278
+
279
+ <!-- Stage Header Badge -->
280
+ <circle cx="28" cy="28" r="16" fill="url(#cyanGrad)"/>
281
+ <text x="28" y="34" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="900" fill="#04141f">6</text>
282
+
283
+ <text x="56" y="34" font-family="sans-serif" font-size="18.5" font-weight="900" fill="#ffffff">OUTPUT SURFACES &amp; REPRODUCIBILITY</text>
284
+ <rect x="635" y="14" width="130" height="28" rx="6" fill="#082f49" stroke="#38bdf8" stroke-width="1.2"/>
285
+ <text x="700" y="32" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="900" fill="#7dd3fc">READ-ONLY</text>
286
+
287
+ <!-- Sub-bullets -->
288
+ <g transform="translate(24, 60)">
289
+ <text x="0" y="16" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#bae6fd">• <tspan font-weight="700">Web UI:</tspan> <tspan fill="#7dd3fc">`praxis web`</tspan> — Security Studio, live SSE, loopback-only, secrets redacted</text>
290
+ <text x="0" y="42" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#bae6fd">• <tspan font-weight="700">Portable Rules:</tspan> <tspan fill="#7dd3fc">`praxis rules export`</tspan> — 411 pattern rules as Semgrep YAML</text>
291
+ <text x="0" y="68" font-family="sans-serif" font-size="14.5" font-weight="600" fill="#bae6fd">• <tspan font-weight="700">Code Scanning:</tspan> SARIF carries numeric <tspan fill="#7dd3fc">`security-severity`</tspan> so alerts rank properly</text>
292
+ <text x="0" y="92" font-family="sans-serif" font-size="14.5" font-weight="700" fill="#34d399">• Reproducible: scan fingerprint + CI determinism gate over <tspan fill="#a7f3d0">`file::rule`</tspan> identities</text>
293
+ </g>
294
+ </g>
295
+
296
+ <!-- ========================================================================= -->
297
+ <!-- FOOTER -->
298
+ <!-- ========================================================================= -->
299
+ <g transform="translate(480, 1300)">
300
+ <text text-anchor="middle" font-family="'Segoe UI', sans-serif" font-size="13.5" font-weight="600" fill="#c084fc">
301
+ Node.js ≥ 18 · Pure ESM · 28 Security Agents · 4-Tier Verification Ladder · Multi-LLM Autopilot
302
+ </text>
303
+ </g>
304
+ </svg>
@@ -0,0 +1,38 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="620" height="180" viewBox="0 0 620 180" role="img" aria-label="Praxis logo">
2
+ <defs>
3
+ <!-- Base Shield Gradient (Vibrant purple to deep violet) -->
4
+ <linearGradient id="purpleGrad" x1="0" y1="0" x2="1" y2="1">
5
+ <stop offset="0%" stop-color="#c084fc"/>
6
+ <stop offset="55%" stop-color="#7c3aed"/>
7
+ <stop offset="100%" stop-color="#4c1d95"/>
8
+ </linearGradient>
9
+ <!-- Wordmark Gradient (Fuchsia to violet) -->
10
+ <linearGradient id="wordGrad" x1="0" y1="0" x2="1" y2="0">
11
+ <stop offset="0%" stop-color="#e879f9"/>
12
+ <stop offset="100%" stop-color="#7c3aed"/>
13
+ </linearGradient>
14
+ </defs>
15
+
16
+ <!-- Shield icon with find-fix-verify loop and AI sparkle -->
17
+ <g transform="translate(24,28)">
18
+ <!-- Sleek outer shield path -->
19
+ <path d="M55 0 L110 18 V62 C110 100 86 128 55 145 C24 128 0 100 0 62 V18 Z"
20
+ fill="url(#purpleGrad)" stroke="#3b0764" stroke-width="2"/>
21
+
22
+ <!-- Clockwise reload/loop arrow (the "remediation loop") -->
23
+ <path d="M55 35 A35 35 0 1 1 20 70 H32 A23 23 0 1 0 55 47 V60 L75 41 L55 22 V35 Z"
24
+ fill="#ffffff" opacity="0.95"/>
25
+
26
+ <!-- 4-point AI sparkle star (representing autopilot / agent intelligence) -->
27
+ <path d="M55 52 Q55 70 73 70 Q55 70 55 88 Q55 70 37 70 Q55 70 55 52 Z"
28
+ fill="#ffffff" opacity="0.95"/>
29
+ </g>
30
+
31
+ <!-- Wordmark -->
32
+ <text x="160" y="86" font-family="Segoe UI, Helvetica, Arial, sans-serif"
33
+ font-size="56" font-weight="800" fill="url(#wordGrad)" letter-spacing="-1">Praxis</text>
34
+
35
+ <!-- Tagline under the wordmark -->
36
+ <text x="162" y="120" font-family="Segoe UI, Helvetica, Arial, sans-serif"
37
+ font-size="19" font-weight="600" fill="#6b7280" letter-spacing="0.4">Autonomous AI-Security Audit Framework</text>
38
+ </svg>
@@ -1,6 +1,6 @@
1
1
  # Launch Day Security Checklist
2
2
 
3
- **Complete this checklist before you go live. Each item takes under 1 minute to verify.**
3
+ Use this checklist to plan release verification. The checks are starting points; their effort and required evidence depend on the application.
4
4
 
5
5
  ---
6
6
 
@@ -13,11 +13,11 @@
13
13
  ```bash
14
14
  curl -I https://yoursite.com/.git/config
15
15
  ```
16
- If you get a 200 response, your git folder is exposed.
16
+ Inspect the response body: a 200 response alone may be a generic application page. Confirm that Git metadata is inaccessible.
17
17
 
18
18
  **Fix:** Configure your web server to deny access to `.git`:
19
19
  - Nginx: `location ~ /\.git { deny all; }`
20
- - Vercel/Netlify: Already blocked by default
20
+ - Hosted platforms: verify the deployed behavior rather than assuming a default
21
21
 
22
22
  ---
23
23
 
@@ -136,7 +136,6 @@ Try accessing:
136
136
  - `/admin`
137
137
  - `/api/admin`
138
138
  - `/dashboard`
139
- - `/_next` (for Next.js internal routes)
140
139
 
141
140
  **Fix:**
142
141
  - Add authentication middleware to all admin routes
@@ -151,7 +150,7 @@ Try accessing:
151
150
  - [ ] **CORS configured:** Not set to `*` in production
152
151
  - [ ] **Cookies secured:** `HttpOnly`, `Secure`, `SameSite` flags set
153
152
  - [ ] **File uploads validated:** Check file types, not just extensions
154
- - [ ] **SQL/NoSQL injection tested:** Try `'; DROP TABLE users;--` in input fields
153
+ - [ ] **SQL/NoSQL injection tested:** Use harmless probes in an authorized test environment and verify parameterized queries
155
154
 
156
155
  ---
157
156
 
@@ -161,8 +160,8 @@ Security is ongoing. Schedule monthly reviews:
161
160
  1. Re-run this checklist
162
161
  2. Check for dependency updates
163
162
  3. Review access logs for suspicious activity
164
- 4. Rotate API keys quarterly
163
+ 4. Review credential exposure and rotate keys according to provider guidance and incident requirements
165
164
 
166
165
  ---
167
166
 
168
- **You've got this. Ship it.**
167
+ Record the evidence, unresolved findings, and the owner of each release decision.
@@ -24,6 +24,7 @@
24
24
 
25
25
  import fs from 'fs';
26
26
  import { BaseAgent, createFinding, ruleTableLineMask } from './base-agent.js';
27
+ import { isDocumentedSecretExample } from '../utils/entropy.js';
27
28
 
28
29
  // =============================================================================
29
30
  // PATTERNS & REGEXES
@@ -304,6 +305,7 @@ export class AgentTelemetryAgent extends BaseAgent {
304
305
  pattern.regex.lastIndex = 0;
305
306
  let match;
306
307
  while ((match = pattern.regex.exec(lines[i])) !== null) {
308
+ if (isDocumentedSecretExample(pattern.rule, match[0])) continue;
307
309
  // Skip placeholder credential values (docs/examples) for the
308
310
  // generic secret-kv rule only.
309
311
  if (pattern.rule === 'AGENT_LOG_SECRET_KV' && PLACEHOLDER_VALUE.test(match[1] || '')) break;
@@ -88,7 +88,7 @@ export const PATTERNS = [
88
88
  {
89
89
  rule: 'API_UPLOAD_NO_TYPE_CHECK',
90
90
  title: 'API: File Upload Without Type Validation',
91
- regex: /(?<!_)(?:originalname|filename)\s*(?:\)|;)/g,
91
+ regex: /\b(?:file|upload|uploadedFile|req\.file|request\.file)\.originalname\s*(?:\)|;)/g,
92
92
  severity: 'high',
93
93
  cwe: 'CWE-434',
94
94
  owasp: 'A04:2021',
@@ -99,7 +99,7 @@ export const PATTERNS = [
99
99
  {
100
100
  rule: 'API_PATH_IN_FILENAME',
101
101
  title: 'API: Path Traversal in File Upload',
102
- regex: /path\.join\s*\([^)]*(?:originalname|filename|req\.file|req\.body)/g,
102
+ regex: /path\.join\s*\([^)]*(?:\b(?:req|request)\.(?:files?|body|query|params)\b|\b[\w$]+\.originalname\b)/g,
103
103
  severity: 'critical',
104
104
  cwe: 'CWE-22',
105
105
  owasp: 'A01:2021',
@@ -10,8 +10,10 @@
10
10
 
11
11
  import { execSync, execFileSync } from 'child_process';
12
12
  import path from 'path';
13
+ import { createHash } from 'crypto';
13
14
  import { BaseAgent, createFinding } from './base-agent.js';
14
15
  import { SECRET_PATTERNS } from '../utils/patterns.js';
16
+ import { isDocumentedSecretExample } from '../utils/entropy.js';
15
17
 
16
18
  // Compile a fast combined regex from all secret patterns
17
19
  const FAST_SECRET_PATTERNS = SECRET_PATTERNS.map(p => ({
@@ -28,6 +30,7 @@ export class GitHistoryScanner extends BaseAgent {
28
30
  async analyze(context) {
29
31
  const { rootPath, options } = context;
30
32
  const findings = [];
33
+ const seen = new Set();
31
34
 
32
35
  // Check if this is a git repository
33
36
  if (!this.isGitRepo(rootPath)) return [];
@@ -50,9 +53,8 @@ export class GitHistoryScanner extends BaseAgent {
50
53
  maxBuffer: 50 * 1024 * 1024, // 50MB buffer
51
54
  timeout: 60000, // 60s timeout
52
55
  });
53
- } catch {
54
- // git log failed — might be a shallow clone or no history
55
- return [];
56
+ } catch (err) {
57
+ throw new Error(`Git history scan failed: ${err.message}`);
56
58
  }
57
59
 
58
60
  if (!diffOutput) return [];
@@ -88,8 +90,12 @@ export class GitHistoryScanner extends BaseAgent {
88
90
  // Check against all secret patterns
89
91
  for (const p of FAST_SECRET_PATTERNS) {
90
92
  p.pattern.lastIndex = 0;
91
- const match = p.pattern.exec(addedLine);
92
- if (match) {
93
+ let match;
94
+ while ((match = p.pattern.exec(addedLine)) !== null) {
95
+ if (isDocumentedSecretExample(p.name, match[0])) continue;
96
+ const key = `${p.name}:${createHash('sha256').update(match[0]).digest('hex')}`;
97
+ if (seen.has(key)) continue;
98
+ seen.add(key);
93
99
  // Check if this secret still exists in current working tree
94
100
  const stillExists = this.existsInWorkingTree(rootPath, match[0]);
95
101
 
@@ -113,18 +119,11 @@ export class GitHistoryScanner extends BaseAgent {
113
119
  }
114
120
  }
115
121
 
116
- // Deduplicate by matched value (same secret in multiple commits)
117
- const seen = new Set();
118
- return findings.filter(f => {
119
- const key = `${f.matched}:${f.title}`;
120
- if (seen.has(key)) return false;
121
- seen.add(key);
122
- return true;
123
- });
122
+ return findings;
124
123
 
125
124
  } catch (err) {
126
- // Don't fail the entire scan if git history scan fails
127
- return [];
125
+ // Let the orchestrator mark this scanner incomplete instead of clean.
126
+ throw new Error(`GitHistoryScanner incomplete: ${err.message}`, { cause: err });
128
127
  }
129
128
  }
130
129
 
@@ -33,6 +33,7 @@ import { buildScanFingerprint, fingerprintLine } from '../utils/scan-fingerprint
33
33
  import { readFixLedger, summarizeFixLedger, isReversible } from '../utils/fix-ledger.js';
34
34
  import { readScoreHistory, summarizeHistory } from '../utils/score-history.js';
35
35
  import { toolVersion } from '../core/version.js';
36
+ import { displayPath } from '../core/paths.js';
36
37
 
37
38
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
38
39
  const PKG_VERSION = toolVersion();
@@ -44,13 +45,12 @@ export class HTMLReporter {
44
45
  }
45
46
 
46
47
  normalizePath(filePath, rootPath) {
47
- if (!filePath) return '';
48
- const norm = String(filePath).replace(/\\/g, '/');
49
- const normRoot = rootPath ? String(rootPath).replace(/\\/g, '/') : '';
50
- if (normRoot && norm.startsWith(normRoot)) {
51
- return norm.slice(normRoot.length).replace(/^\/+/, '');
52
- }
53
- return norm.replace(/^[a-zA-Z]:\/+/, '').replace(/^.*\/Praxis\/showcase-target\//, '').replace(/^.*\/showcase-target\//, '');
48
+ // Paths reach the reporter already normalised by the orchestrator, so this only
49
+ // has to fall back for callers that build findings themselves. The strippers
50
+ // that used to live here leaked the username into every HTML report and
51
+ // truncated any real path containing a directory called `Praxis` — see
52
+ // cli/core/paths.js.
53
+ return displayPath(filePath, rootPath);
54
54
  }
55
55
 
56
56
  /**
@@ -177,6 +177,7 @@ export class HTMLReporter {
177
177
  </div>
178
178
  </div>
179
179
  </header>
180
+ ${scoreResult.scanComplete === false ? '<p role="alert" class="sev-badge sev-high">SCAN INCOMPLETE — score reflects only available results. Review scan errors before trusting this report.</p>' : ''}
180
181
  `;
181
182
  }
182
183
 
@@ -1122,4 +1123,4 @@ function toggleDetail(id) {
1122
1123
  }
1123
1124
  }
1124
1125
 
1125
- export default HTMLReporter;
1126
+ export default HTMLReporter;