ship-safe 6.3.0 → 7.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/README.md CHANGED
@@ -18,9 +18,9 @@
18
18
 
19
19
  18 security agents. 80+ attack classes. One command.
20
20
 
21
- **Ship Safe v6.2.0** is an AI-powered security platform that runs 18 specialized agents in parallel against your codebase, scanning for secrets, injection vulnerabilities, auth bypass, SSRF, supply chain attacks, Supabase RLS misconfigs, Docker/Terraform/Kubernetes misconfigs, CI/CD pipeline poisoning, LLM/agentic AI security, MCP server misuse, RAG poisoning, PII compliance, vibe coding patterns, exception handling, AI agent config security, and more. OWASP 2025 scoring with EPSS exploit probability. LLM-powered deep analysis verifies exploitability of critical findings. Secrets verification probes provider APIs to check if leaked keys are still active. Compliance mapping to SOC 2, ISO 27001, and NIST AI RMF. Built-in threat intelligence feed with offline-first IOC matching. CI integration with GitHub PR comments, threshold gating, and SARIF output.
21
+ **Ship Safe v6.4.0** is an AI-powered security platform that runs 18 specialized agents in parallel against your codebase, scanning for secrets, injection vulnerabilities, auth bypass, SSRF, supply chain attacks, Supabase RLS misconfigs, Docker/Terraform/Kubernetes misconfigs, CI/CD pipeline poisoning, LLM/agentic AI security, MCP server misuse, RAG poisoning, PII compliance, vibe coding patterns, exception handling, AI agent config security, and more. OWASP 2025 scoring with EPSS exploit probability. LLM-powered deep analysis verifies exploitability of critical findings. Secrets verification probes provider APIs to check if leaked keys are still active. Compliance mapping to SOC 2, ISO 27001, and NIST AI RMF. Built-in threat intelligence feed with offline-first IOC matching. CI integration with GitHub PR comments, threshold gating, and SARIF output.
22
22
 
23
- **v6.2.0 highlights:** Real-time Claude Code hooks (`npx ship-safe hooks install`) block secrets before they land on disk. Universal LLM support — use Groq, Together AI, Mistral, DeepSeek, xAI, Perplexity, LM Studio, or any OpenAI-compatible endpoint for deep analysis. Supply chain IOC matching for known-compromised packages and CanisterWorm-style ICP blockchain C2 indicators.
23
+ **v6.4.0 highlights:** MCP server scanning (`npx ship-safe scan-mcp`) vets tool manifests for prompt injection and credential harvesting before you connect. Detection support for openclaude and claw-code the two most-starred Claude Code forks from the March 2026 source leak with accurate config scanning based on their actual architectures. Four new CI/CD patterns flag AI agent danger modes in pipelines. Legal dataset corrected: claw-code reclassified as a clean-room rewrite, not a leaked-source derivative.
24
24
 
25
25
  [Documentation](https://shipsafecli.com/docs) | [Blog](https://shipsafecli.com/blog) | [Pricing](https://shipsafecli.com/pricing)
26
26
 
@@ -74,8 +74,6 @@ npx ship-safe hooks status
74
74
  npx ship-safe hooks remove
75
75
  ```
76
76
 
77
- ![ship-safe terminal demo](.github/assets/ship%20safe%20terminal.jpg)
78
-
79
77
  ---
80
78
 
81
79
  ## The `audit` Command
@@ -169,10 +167,10 @@ npx ship-safe audit .
169
167
  | **PIIComplianceAgent** | Compliance | PII detection — SSNs, credit cards, emails, phone numbers in source code, logs, and configs |
170
168
  | **VibeCodingAgent** | Code Vulns | AI-generated code patterns — no input validation, empty catch blocks, hardcoded secrets, disabled security features, TODO-auth patterns |
171
169
  | **ExceptionHandlerAgent** | Code Vulns | OWASP A10:2025 — empty catch blocks, unhandled promise rejections, missing React error boundaries, leaked stack traces, generic catch-all without rethrow |
172
- | **AgentConfigScanner** | AI/LLM | AI agent config security — prompt injection in .cursorrules/CLAUDE.md/AGENTS.md/.windsurfrules, malicious Claude Code hooks (CVE-2026), OpenClaw public binding & malicious skills, encoded/obfuscated payloads, data exfiltration instructions, agent memory poisoning |
170
+ | **AgentConfigScanner** | AI/LLM | AI agent config security — prompt injection in .cursorrules/CLAUDE.md/AGENTS.md/.windsurfrules, malicious Claude Code hooks (CVE-2026), OpenClaw public binding & malicious skills, openclaude profile file (`OPENAI_BASE_URL` over http://), claw-code config (`danger-full-access`, disabled sandbox, shell hooks, insecure MCP transports), encoded/obfuscated payloads, data exfiltration instructions, agent memory poisoning |
173
171
  | **MobileScanner** | Mobile | OWASP Mobile Top 10 2024 — insecure storage, WebView JS injection, HTTP endpoints, excessive permissions, debug mode |
174
172
  | **GitHistoryScanner** | Secrets | Leaked secrets in git commit history (checks if still active in working tree) |
175
- | **CICDScanner** | CI/CD | OWASP CI/CD Top 10 — pipeline poisoning, unpinned actions, secret logging, self-hosted runners, script injection |
173
+ | **CICDScanner** | CI/CD | OWASP CI/CD Top 10 — pipeline poisoning, unpinned actions, secret logging, self-hosted runners, script injection, AI agent danger flags (`--dangerously-skip-permissions`, insecure provider URLs in CI) |
176
174
  | **APIFuzzer** | API | Routes without auth, missing input validation, mass assignment, unrestricted file upload, GraphQL introspection, debug endpoints, missing rate limiting, OpenAPI spec security issues |
177
175
  | **ReconAgent** | Recon | Attack surface discovery — frameworks, languages, auth patterns, databases, cloud providers, IaC, CI/CD pipelines |
178
176
 
@@ -299,13 +297,13 @@ npx ship-safe audit . --verify
299
297
  npx ship-safe doctor
300
298
  ```
301
299
 
302
- ### OpenClaw Security
300
+ ### Agent Security
303
301
 
304
302
  ```bash
305
303
  # Focused OpenClaw security scan
306
304
  npx ship-safe openclaw .
307
305
 
308
- # Auto-harden OpenClaw configs (0.0.0.0127.0.0.1, add auth, wswss)
306
+ # Auto-harden OpenClaw configs (0.0.0.0->127.0.0.1, add auth, ws->wss)
309
307
  npx ship-safe openclaw . --fix
310
308
 
311
309
  # Red team: simulate ClawJacked, prompt injection, data exfil attacks
@@ -319,6 +317,14 @@ npx ship-safe scan-skill https://clawhub.io/skills/some-skill
319
317
  npx ship-safe scan-skill ./local-skill.json
320
318
  npx ship-safe scan-skill --all # Scan all skills from openclaw.json
321
319
 
320
+ # Scan an MCP server's tool manifest before connecting
321
+ npx ship-safe scan-mcp https://your-mcp-server/
322
+ npx ship-safe scan-mcp ./local-manifest.json
323
+ npx ship-safe scan-mcp https://your-mcp-server/ --json
324
+
325
+ # Legal risk audit — DMCA, leaked-source derivatives (openclaude, claw-code-js), IP disputes
326
+ npx ship-safe legal .
327
+
322
328
  # Generate hardened OpenClaw config
323
329
  npx ship-safe init --openclaw
324
330
 
@@ -326,6 +332,20 @@ npx ship-safe init --openclaw
326
332
  npx ship-safe abom .
327
333
  ```
328
334
 
335
+ #### openclaude and claw-code
336
+
337
+ Ship Safe detects security issues in both major Claude Code forks from the March 2026 source leak.
338
+
339
+ **openclaude** (`@gitlawb/openclaude`) is a CLI tool that routes Claude Code's toolset through any OpenAI-compatible provider. Its only persistent file artifact is `.openclaude-profile.json`. Ship Safe flags:
340
+ - `OPENAI_BASE_URL` using `http://` for non-localhost endpoints (unencrypted LLM traffic)
341
+ - The profile file present in a project not covered by `.gitignore` (API key exposure risk)
342
+
343
+ **claw-code** (`ultraworkers/claw-code`) is a clean-room Rust + Python rewrite of Claude Code's agent harness. Its config lives in `.claw.json`, `.claw/settings.json`, and `.claw/settings.local.json`. Ship Safe flags:
344
+ - `permissionMode: danger-full-access` or `dangerouslySkipPermissions: true` (no confirmation on any tool call)
345
+ - `sandbox.enabled: false` (filesystem isolation removed)
346
+ - Hook commands containing shell execution or remote download patterns
347
+ - MCP server connections over `ws://` or `http://` to non-localhost hosts
348
+
329
349
  ### Threat Intelligence
330
350
 
331
351
  ```bash
@@ -37,11 +37,24 @@ const AGENT_RULES_FILES = [
37
37
  '.github/copilot-instructions.md',
38
38
  '.aider.conf.yml',
39
39
  '.continue/config.json',
40
+ // Gemini CLI
41
+ '.gemini/settings.json',
42
+ '.gemini/rules.md',
43
+ // Cody (Sourcegraph)
44
+ '.cody/config.json',
45
+ '.cody/context.json',
46
+ // Augment Code
47
+ '.augment/config.json',
40
48
  ];
41
49
 
42
50
  const AGENT_RULES_GLOBS = [
43
51
  '.cursor/rules/*.mdc',
44
52
  '.claude/commands/*.md',
53
+ // Gemini CLI commands
54
+ '.gemini/commands/*.md',
55
+ // Cody custom commands
56
+ '.cody/commands/*.md',
57
+ '.cody/rules/*.md',
45
58
  ];
46
59
 
47
60
  const OPENCLAW_FILES = [
@@ -54,10 +67,38 @@ const OPENCLAW_GLOBS = [
54
67
  '.openclaw/**/*.json',
55
68
  ];
56
69
 
70
+ // openclaude (github.com/Gitlawb/openclaude) — Claude Code fork with
71
+ // OpenAI-compatible provider shim. Config is purely via environment variables
72
+ // (CLAUDE_CODE_USE_OPENAI, OPENAI_BASE_URL, OPENAI_MODEL, OPENAI_API_KEY).
73
+ // The only persistent file artifact is .openclaude-profile.json, which stores
74
+ // named profiles as { name, env: { OPENAI_BASE_URL, OPENAI_API_KEY, ... } }.
75
+ const OPENCLAUDE_PROFILE_FILES = [
76
+ '.openclaude-profile.json',
77
+ ];
78
+
79
+ // claw-code (github.com/instructkr/claw-code, now ultraworkers/claw-code) —
80
+ // Rust + Python clean-room rewrite of Claude Code's agent harness.
81
+ // CLI tool (`claw` binary). NOT a server — no port binding outside tests.
82
+ // Config files: .claw.json (project root), .claw/settings.json,
83
+ // .claw/settings.local.json, ~/.claw.json, ~/.claw/settings.json
84
+ // Auth: ANTHROPIC_API_KEY, OPENAI_API_KEY, or XAI_API_KEY env vars.
85
+ // Permission modes: read-only, workspace-write, danger-full-access, prompt, allow.
86
+ // --dangerously-skip-permissions flag disables all permission checks.
87
+ // Sandbox: SandboxConfig with FilesystemIsolationMode (workspace-only default).
88
+ // Hooks: preToolUse / postToolUse arrays in settings JSON.
89
+ // MCP: mcpServers in settings JSON (stdio, sse, http, ws transports).
90
+ const CLAW_CODE_FILES = [
91
+ '.claw.json',
92
+ '.claw/settings.json',
93
+ '.claw/settings.local.json',
94
+ ];
95
+
57
96
  const MEMORY_GLOBS = [
58
97
  '.claude/memory/**',
59
98
  '.cursor/memory/**',
60
99
  '.continue/memory/**',
100
+ '.gemini/memory/**',
101
+ '.cody/memory/**',
61
102
  ];
62
103
 
63
104
  // =============================================================================
@@ -230,6 +271,18 @@ export class AgentConfigScanner extends BaseAgent {
230
271
  findings = findings.concat(this._scanOpenClawConfig(file));
231
272
  }
232
273
 
274
+ // ── 3b. Scan openclaude profile files ─────────────────────────────────
275
+ for (const file of discovered.openclaudeFiles) {
276
+ findings = findings.concat(this.scanFileWithPatterns(file, PATTERNS));
277
+ findings = findings.concat(this._scanOpenClaudeProfile(file));
278
+ }
279
+
280
+ // ── 3c. Scan claw-code config files ────────────────────────────────────
281
+ for (const file of discovered.clawCodeFiles) {
282
+ findings = findings.concat(this.scanFileWithPatterns(file, PATTERNS));
283
+ findings = findings.concat(this._scanClawCodeConfig(file));
284
+ }
285
+
233
286
  // ── 4. Scan Claude Code hooks ──────────────────────────────────────────
234
287
  for (const file of discovered.claudeSettingsFiles) {
235
288
  findings = findings.concat(this._scanClaudeHooks(file));
@@ -297,7 +350,21 @@ export class AgentConfigScanner extends BaseAgent {
297
350
  memoryFiles.push(...globbed);
298
351
  } catch { /* skip */ }
299
352
 
300
- return { rulesFiles, openclawFiles, claudeSettingsFiles, memoryFiles };
353
+ // ── openclaude profile files ─────────────────────────────────────────────
354
+ const openclaudeFiles = [];
355
+ for (const rel of OPENCLAUDE_PROFILE_FILES) {
356
+ const full = path.join(rootPath, rel);
357
+ if (fs.existsSync(full)) openclaudeFiles.push(full);
358
+ }
359
+
360
+ // ── claw-code config files ────────────────────────────────────────────────
361
+ const clawCodeFiles = [];
362
+ for (const rel of CLAW_CODE_FILES) {
363
+ const full = path.join(rootPath, rel);
364
+ if (fs.existsSync(full)) clawCodeFiles.push(full);
365
+ }
366
+
367
+ return { rulesFiles, openclawFiles, openclaudeFiles, clawCodeFiles, claudeSettingsFiles, memoryFiles };
301
368
  }
302
369
 
303
370
  // ===========================================================================
@@ -415,6 +482,178 @@ export class AgentConfigScanner extends BaseAgent {
415
482
  return findings;
416
483
  }
417
484
 
485
+ /**
486
+ * Scan .openclaude-profile.json for security issues.
487
+ *
488
+ * openclaude (github.com/Gitlawb/openclaude) is a CLI tool, not a server.
489
+ * There is no config file, no host/port binding, no auth mechanism.
490
+ * All configuration is via environment variables:
491
+ * CLAUDE_CODE_USE_OPENAI=1, OPENAI_BASE_URL, OPENAI_MODEL, OPENAI_API_KEY
492
+ *
493
+ * The only persistent file artifact is .openclaude-profile.json, which stores
494
+ * named profiles as { name: string, env: { OPENAI_BASE_URL, OPENAI_API_KEY, ... } }.
495
+ * openclaude ships with this file in its default .gitignore.
496
+ *
497
+ * Security risk: if OPENAI_BASE_URL is an http:// (non-TLS) endpoint, all
498
+ * LLM traffic (prompts, code context, responses) is sent unencrypted.
499
+ */
500
+ _scanOpenClaudeProfile(filePath) {
501
+ const content = this.readFile(filePath);
502
+ if (!content) return [];
503
+ const findings = [];
504
+
505
+ let profile;
506
+ try { profile = JSON.parse(content); } catch { return []; }
507
+
508
+ const env = profile.env || {};
509
+
510
+ // ── Insecure provider URL (http:// for non-localhost) ─────────────────
511
+ const baseUrl = env.OPENAI_BASE_URL || '';
512
+ if (baseUrl && /^http:\/\/(?!localhost|127\.0\.0\.1|::1)/i.test(baseUrl)) {
513
+ findings.push(createFinding({
514
+ file: filePath, line: 1,
515
+ severity: 'high',
516
+ category: this.category,
517
+ rule: 'OPENCLAUDE_INSECURE_PROVIDER_URL',
518
+ title: 'openclaude: LLM Provider URL Without TLS',
519
+ description:
520
+ `openclaude routes model calls to ${baseUrl} over plain HTTP. ` +
521
+ 'Prompts, code context, and model responses are sent unencrypted. ' +
522
+ 'A network attacker can read or modify all LLM interactions in transit.',
523
+ matched: `OPENAI_BASE_URL: "${baseUrl}"`,
524
+ confidence: 'high',
525
+ cwe: 'CWE-319',
526
+ owasp: 'A02:2021',
527
+ fix: 'Use an https:// provider URL. Never route LLM traffic over plaintext HTTP on untrusted networks.',
528
+ }));
529
+ }
530
+
531
+ return findings;
532
+ }
533
+
534
+ /**
535
+ * Scan claw-code config files (.claw.json, .claw/settings.json, .claw/settings.local.json)
536
+ * for insecure settings.
537
+ *
538
+ * claw-code (ultraworkers/claw-code) is a Rust + Python clean-room rewrite of Claude Code.
539
+ * It is a CLI tool — no server port binding. Config lives in JSON settings files.
540
+ *
541
+ * Checked settings:
542
+ * - hooks.preToolUse / hooks.postToolUse: shell hook commands (RCE vector)
543
+ * - permissions.dangerouslySkipPermissions / permissionMode: "danger-full-access"
544
+ * - sandbox.enabled: false (filesystem isolation disabled)
545
+ * - mcpServers with insecure ws:// or http:// remote URLs (MiTM risk)
546
+ * - mcpServers using env vars that could expose credentials
547
+ */
548
+ _scanClawCodeConfig(filePath) {
549
+ const content = this.readFile(filePath);
550
+ if (!content) return [];
551
+ const findings = [];
552
+
553
+ let config;
554
+ try { config = JSON.parse(content); } catch { return []; }
555
+
556
+ // ── Dangerous permission mode ─────────────────────────────────────────
557
+ const permMode = config.permissionMode ?? config.permissions?.mode ?? '';
558
+ const skipPerms = config.dangerouslySkipPermissions ??
559
+ config.permissions?.dangerouslySkipPermissions ?? false;
560
+
561
+ if (skipPerms === true || permMode === 'danger-full-access') {
562
+ findings.push(createFinding({
563
+ file: filePath, line: 1,
564
+ severity: 'high',
565
+ category: this.category,
566
+ rule: 'CLAW_CODE_SKIP_PERMISSIONS',
567
+ title: 'claw-code: All Permission Checks Disabled',
568
+ description:
569
+ 'claw-code is configured with dangerously-skip-permissions or permissionMode: danger-full-access. ' +
570
+ 'Every tool call executes without asking for user confirmation. ' +
571
+ 'A single prompt injection in any file the agent reads can trigger unrestricted shell execution or file writes.',
572
+ matched: skipPerms ? 'dangerouslySkipPermissions: true' : `permissionMode: "${permMode}"`,
573
+ confidence: 'high',
574
+ cwe: 'CWE-269',
575
+ owasp: 'ASI03',
576
+ fix: 'Set permissionMode to "workspace-write" or "prompt". Only use danger-full-access in fully isolated environments.',
577
+ }));
578
+ }
579
+
580
+ // ── Sandbox disabled ──────────────────────────────────────────────────
581
+ if (config.sandbox?.enabled === false) {
582
+ findings.push(createFinding({
583
+ file: filePath, line: 1,
584
+ severity: 'medium',
585
+ category: this.category,
586
+ rule: 'CLAW_CODE_SANDBOX_DISABLED',
587
+ title: 'claw-code: Filesystem Sandbox Disabled',
588
+ description:
589
+ 'claw-code sandbox is explicitly disabled. By default claw-code restricts ' +
590
+ 'filesystem access to the workspace directory. With sandbox off, tools can ' +
591
+ 'read and write anywhere on the system.',
592
+ matched: 'sandbox.enabled: false',
593
+ confidence: 'high',
594
+ cwe: 'CWE-732',
595
+ owasp: 'ASI03',
596
+ fix: 'Remove sandbox.enabled: false or set filesystem-mode to workspace-only.',
597
+ }));
598
+ }
599
+
600
+ // ── Hooks with shell commands ──────────────────────────────────────────
601
+ const hookLists = [
602
+ ...(config.hooks?.preToolUse || []),
603
+ ...(config.hooks?.postToolUse || []),
604
+ ];
605
+ for (const hook of hookLists) {
606
+ const cmd = typeof hook === 'string' ? hook : (hook.command || hook.cmd || hook.run || '');
607
+ if (!cmd) continue;
608
+ if (/(?:bash\s+-c|sh\s+-c|cmd\s+\/c|powershell\s+-|pwsh\s+-)/i.test(cmd) ||
609
+ /\|\s*(?:bash|sh|zsh|node|python)/i.test(cmd) ||
610
+ /(?:curl|wget)\s+https?:\/\/(?!localhost|127\.0\.0\.1)/i.test(cmd)) {
611
+ findings.push(createFinding({
612
+ file: filePath, line: 1,
613
+ severity: 'critical',
614
+ category: this.category,
615
+ rule: 'CLAW_CODE_HOOK_SHELL',
616
+ title: 'claw-code: Dangerous Hook Command',
617
+ description:
618
+ 'claw-code hook contains a shell execution or remote download command. ' +
619
+ 'A malicious .claw.json in a repository can achieve RCE when anyone ' +
620
+ 'opens the project with claw.',
621
+ matched: cmd.substring(0, 150),
622
+ confidence: 'high',
623
+ cwe: 'CWE-94',
624
+ owasp: 'ASI04',
625
+ fix: 'Remove shell execution hooks. Use only safe, scoped commands in claw hooks.',
626
+ }));
627
+ }
628
+ }
629
+
630
+ // ── MCP servers with insecure remote URLs ─────────────────────────────
631
+ const mcpServers = config.mcpServers || {};
632
+ for (const [name, srv] of Object.entries(mcpServers)) {
633
+ const url = typeof srv === 'object' ? (srv.url || '') : '';
634
+ if (/^(?:ws|http):\/\/(?!localhost|127\.0\.0\.1|::1)/i.test(url)) {
635
+ findings.push(createFinding({
636
+ file: filePath, line: 1,
637
+ severity: 'high',
638
+ category: this.category,
639
+ rule: 'CLAW_CODE_MCP_INSECURE_URL',
640
+ title: `claw-code: MCP Server "${name}" Uses Unencrypted Transport`,
641
+ description:
642
+ `MCP server "${name}" connects to ${url} over an unencrypted channel (ws:// or http://). ` +
643
+ 'All MCP messages — tool calls, results, and any code context — are sent in plaintext. ' +
644
+ 'A network attacker can intercept or inject MCP responses to hijack the agent.',
645
+ matched: url,
646
+ confidence: 'high',
647
+ cwe: 'CWE-319',
648
+ owasp: 'A02:2021',
649
+ fix: 'Use wss:// or https:// for all non-localhost MCP server connections.',
650
+ }));
651
+ }
652
+ }
653
+
654
+ return findings;
655
+ }
656
+
418
657
  /**
419
658
  * Scan .claude/settings.json for malicious hooks.
420
659
  * Based on Check Point Research disclosure: hooks in settings.json
@@ -199,6 +199,48 @@ const PATTERNS = [
199
199
  description: 'GitHub expression in run step. Attacker-controlled values can inject shell commands.',
200
200
  fix: 'Use environment variables: env: TITLE: ${{ github.event.issue.title }} then run: echo "$TITLE"',
201
201
  },
202
+
203
+ // ── AI Agent CLI — dangerous flags in CI ──────────────────────────────────
204
+ {
205
+ rule: 'CICD_AGENT_SKIP_PERMISSIONS',
206
+ title: 'CI/CD: AI Agent Running Without Permission Checks',
207
+ regex: /(?:--dangerously-skip-permissions|--skip-permissions|permissionMode\s*[=:]\s*["']?danger-full-access["']?)/g,
208
+ severity: 'critical',
209
+ cwe: 'CWE-269',
210
+ owasp: 'ASI03',
211
+ description: 'AI agent CLI flag disables all permission checks. In CI, this means any prompt injection in workspace files can execute arbitrary commands with no confirmation gate.',
212
+ fix: 'Remove --dangerously-skip-permissions. Use --permission-mode=workspace-write for CI automation or scope tool access with --allowedTools.',
213
+ },
214
+ {
215
+ rule: 'CICD_AGENT_INSECURE_PROVIDER',
216
+ title: 'CI/CD: AI Agent Routing to Non-TLS Provider',
217
+ regex: /(?:OPENAI_BASE_URL|ANTHROPIC_BASE_URL|XAI_BASE_URL|CLAUDE_CODE_USE_OPENAI)\s*=\s*["']?http:\/\/(?!localhost|127\.0\.0\.1|::1)/g,
218
+ severity: 'high',
219
+ cwe: 'CWE-319',
220
+ owasp: 'A02:2021',
221
+ description: 'AI agent provider URL uses plain HTTP for a non-localhost endpoint. All prompts, code context, and model responses are transmitted unencrypted in CI.',
222
+ fix: 'Use https:// for all non-localhost AI provider base URLs.',
223
+ },
224
+ {
225
+ rule: 'CICD_OPENCLAUDE_IN_CI',
226
+ title: 'CI/CD: openclaude Running in CI Pipeline',
227
+ regex: /(?:^|\s)openclaude\s/gm,
228
+ severity: 'medium',
229
+ cwe: 'CWE-1188',
230
+ owasp: 'ASI03',
231
+ description: 'openclaude (Claude Code fork with OpenAI-compatible shim) is invoked in CI. Verify OPENAI_BASE_URL is https://, OPENAI_API_KEY is stored as a secret, and .openclaude-profile.json is not committed.',
232
+ fix: 'Ensure OPENAI_API_KEY is a CI secret, OPENAI_BASE_URL uses https://, and .openclaude-profile.json is gitignored.',
233
+ },
234
+ {
235
+ rule: 'CICD_CLAW_DANGER_MODE',
236
+ title: 'CI/CD: claw-code Running in Danger Mode',
237
+ regex: /(?:^|\s)claw\s[^\n]*--dangerously-skip-permissions/gm,
238
+ severity: 'critical',
239
+ cwe: 'CWE-269',
240
+ owasp: 'ASI03',
241
+ description: 'claw-code (Rust/Python Claude Code rewrite) is invoked with --dangerously-skip-permissions in CI. Any prompt injection in the workspace executes without confirmation.',
242
+ fix: 'Remove --dangerously-skip-permissions. Use --permission-mode=workspace-write for CI automation.',
243
+ },
202
244
  ];
203
245
 
204
246
  export class CICDScanner extends BaseAgent {
@@ -25,8 +25,15 @@ import { createProvider, autoDetectProvider } from '../providers/llm-provider.js
25
25
  // CONSTANTS
26
26
  // =============================================================================
27
27
 
28
- /** Max file content to send per finding (tokens are expensive) */
29
- const MAX_FILE_CHARS = 4000;
28
+ /** Max file content per finding for standard providers (tokens cost money) */
29
+ const MAX_FILE_CHARS_DEFAULT = 4000;
30
+
31
+ /**
32
+ * Max file content per finding for large-context providers (Gemma 4 128K–256K).
33
+ * Sending the full file enables cross-function taint tracing that a 40-line
34
+ * window cannot catch.
35
+ */
36
+ const MAX_FILE_CHARS_LARGE_CTX = 80000;
30
37
 
31
38
  /** Max findings to analyze per run (cost control) */
32
39
  const MAX_FINDINGS = 30;
@@ -84,6 +91,14 @@ export class DeepAnalyzer {
84
91
  this.verbose = options.verbose || false;
85
92
  this.spentCents = 0;
86
93
  this.analyzedCount = 0;
94
+
95
+ // If the provider advertises a large context window (Gemma 4, etc.),
96
+ // increase file context and batch size to take full advantage.
97
+ const ctxWindow = this.provider?.contextWindow ?? 0;
98
+ this.largeContext = ctxWindow >= 65536;
99
+ this.maxFileChars = this.largeContext ? MAX_FILE_CHARS_LARGE_CTX : MAX_FILE_CHARS_DEFAULT;
100
+ // Larger batches for local large-context models (no per-token cost)
101
+ this.batchSize = this.largeContext ? 15 : 5;
87
102
  }
88
103
 
89
104
  /**
@@ -91,11 +106,11 @@ export class DeepAnalyzer {
91
106
  * Returns null if no provider is available.
92
107
  */
93
108
  static create(rootPath, options = {}) {
94
- // --local flag: use Ollama
109
+ // --local flag: use Gemma 4 via Ollama (structured output, large context)
95
110
  if (options.local) {
96
- const provider = createProvider('ollama', null, {
97
- model: options.model || 'llama3.2',
98
- baseUrl: options.ollamaUrl || 'http://localhost:11434/api/chat',
111
+ const provider = createProvider('gemma4', null, {
112
+ model: options.model,
113
+ baseUrl: options.ollamaUrl,
99
114
  });
100
115
  return new DeepAnalyzer({ provider, ...options });
101
116
  }
@@ -141,11 +156,10 @@ export class DeepAnalyzer {
141
156
  toAnalyze.length = Math.max(1, affordable);
142
157
  }
143
158
 
144
- // Batch findings (5 per request to balance cost vs. context)
145
- const batchSize = 5;
159
+ // Batch findings larger batches for large-context providers (Gemma 4 etc.)
146
160
  const results = new Map();
147
161
 
148
- for (let i = 0; i < toAnalyze.length; i += batchSize) {
162
+ for (let i = 0; i < toAnalyze.length; i += this.batchSize) {
149
163
  // Budget check before each batch
150
164
  if (this.spentCents >= this.budgetCents) {
151
165
  if (this.verbose) {
@@ -154,7 +168,7 @@ export class DeepAnalyzer {
154
168
  break;
155
169
  }
156
170
 
157
- const batch = toAnalyze.slice(i, i + batchSize);
171
+ const batch = toAnalyze.slice(i, i + this.batchSize);
158
172
  const prompt = this._buildPrompt(batch, context);
159
173
 
160
174
  try {
@@ -261,16 +275,22 @@ ${JSON.stringify(items, null, 2)}`;
261
275
  const lines = content.split('\n');
262
276
  const lineNum = finding.line || 1;
263
277
 
264
- // Get a window of ~40 lines around the finding
265
- const start = Math.max(0, lineNum - 21);
266
- const end = Math.min(lines.length, lineNum + 20);
267
- let context = lines.slice(start, end)
268
- .map((l, i) => `${start + i + 1}: ${l}`)
269
- .join('\n');
278
+ let context;
279
+ if (this.largeContext) {
280
+ // Large-context providers (Gemma 4): send the entire file so the model
281
+ // can trace taint flows across functions, not just the immediate window.
282
+ context = lines.map((l, i) => `${i + 1}: ${l}`).join('\n');
283
+ } else {
284
+ // Standard providers: 40-line window around the finding
285
+ const start = Math.max(0, lineNum - 21);
286
+ const end = Math.min(lines.length, lineNum + 20);
287
+ context = lines.slice(start, end)
288
+ .map((l, i) => `${start + i + 1}: ${l}`)
289
+ .join('\n');
290
+ }
270
291
 
271
- // Truncate if too long
272
- if (context.length > MAX_FILE_CHARS) {
273
- context = context.slice(0, MAX_FILE_CHARS) + '\n... (truncated)';
292
+ if (context.length > this.maxFileChars) {
293
+ context = context.slice(0, this.maxFileChars) + '\n... (truncated)';
274
294
  }
275
295
 
276
296
  return context;
@@ -26,6 +26,7 @@ export { PIIComplianceAgent } from './pii-compliance-agent.js';
26
26
  export { VibeCodingAgent } from './vibe-coding-agent.js';
27
27
  export { ExceptionHandlerAgent } from './exception-handler-agent.js';
28
28
  export { AgentConfigScanner } from './agent-config-scanner.js';
29
+ export { MemoryPoisoningAgent } from './memory-poisoning-agent.js';
29
30
  export { LegalRiskAgent, LEGALLY_RISKY_PACKAGES } from './legal-risk-agent.js';
30
31
  export { ABOMGenerator } from './abom-generator.js';
31
32
  export { VerifierAgent } from './verifier-agent.js';
@@ -36,7 +37,7 @@ export { PolicyEngine } from './policy-engine.js';
36
37
  export { HTMLReporter } from './html-reporter.js';
37
38
 
38
39
  /**
39
- * Create a fully configured orchestrator with all 16 scanning agents.
40
+ * Create a fully configured orchestrator with all 19 scanning agents.
40
41
  * (VerifierAgent and DeepAnalyzer run as post-processors, not in the agent pool.)
41
42
  */
42
43
  import { Orchestrator as OrchestratorClass } from './orchestrator.js';
@@ -58,6 +59,7 @@ import { PIIComplianceAgent as PIIComplianceAgentClass } from './pii-compliance-
58
59
  import { VibeCodingAgent as VibeCodingAgentClass } from './vibe-coding-agent.js';
59
60
  import { ExceptionHandlerAgent as ExceptionHandlerAgentClass } from './exception-handler-agent.js';
60
61
  import { AgentConfigScanner as AgentConfigScannerClass } from './agent-config-scanner.js';
62
+ import { MemoryPoisoningAgent as MemoryPoisoningAgentClass } from './memory-poisoning-agent.js';
61
63
 
62
64
  export function buildOrchestrator() {
63
65
  const orchestrator = new OrchestratorClass();
@@ -80,6 +82,7 @@ export function buildOrchestrator() {
80
82
  new VibeCodingAgentClass(),
81
83
  new ExceptionHandlerAgentClass(),
82
84
  new AgentConfigScannerClass(),
85
+ new MemoryPoisoningAgentClass(),
83
86
  ]);
84
87
  return orchestrator;
85
88
  }
@@ -38,22 +38,14 @@ export const LEGALLY_RISKY_PACKAGES = [
38
38
  // Anthropic's Claude Code source was accidentally leaked. Several repos
39
39
  // appeared immediately; Anthropic filed DMCA takedowns but derivatives
40
40
  // remain online. Shipping any of these exposes you to IP liability.
41
+ //
42
+ // NOTE: The instructkr/claw-code repo (now ultraworkers/claw-code) has since
43
+ // pivoted to a clean-room Rust + Python rewrite and explicitly removed the
44
+ // leaked snapshot. The GitHub repo itself is no longer a DMCA concern.
45
+ // However, any claw-code npm package published in the March 31–April 2 2026
46
+ // window may have contained the leaked TypeScript source before the pivot.
47
+ // Flag early versions as a precaution; assess the specific published version.
41
48
  // ---------------------------------------------------------------------------
42
- {
43
- name: 'claw-code',
44
- versions: '*',
45
- ecosystem: 'npm',
46
- risk: 'dmca',
47
- severity: 'high',
48
- detail:
49
- 'Derived from leaked Anthropic Claude Code source (March 2026). ' +
50
- 'Anthropic has filed DMCA takedown notices. Shipping this package ' +
51
- 'may expose your project to IP infringement liability.',
52
- references: [
53
- 'https://cybernews.com/security/anthropic-claude-code-source-leak/',
54
- 'https://venturebeat.com/technology/claude-codes-source-code-appears-to-have-leaked-heres-what-we-know',
55
- ],
56
- },
57
49
  {
58
50
  name: 'claw-code-js',
59
51
  versions: '*',
@@ -81,6 +73,40 @@ export const LEGALLY_RISKY_PACKAGES = [
81
73
  'https://cybernews.com/security/anthropic-claude-code-source-leak/',
82
74
  ],
83
75
  },
76
+ // ---------------------------------------------------------------------------
77
+ // openclaude (github.com/Gitlawb/openclaude)
78
+ // Claude Code fork that routes to any LLM via OpenAI-compatible shim.
79
+ // Derived directly from the leaked Anthropic source (March 31 2026).
80
+ // Under active DMCA enforcement alongside claw-code.
81
+ // ---------------------------------------------------------------------------
82
+ {
83
+ name: 'openclaude',
84
+ versions: '*',
85
+ ecosystem: 'npm',
86
+ risk: 'leaked-source',
87
+ severity: 'high',
88
+ detail:
89
+ 'openclaude is a fork of the leaked Anthropic Claude Code source (March 2026) ' +
90
+ 'that adds an OpenAI-compatible provider shim. The underlying ~512,000 lines of ' +
91
+ 'TypeScript are Anthropic proprietary IP under active DMCA enforcement. ' +
92
+ 'Additionally ships with auth disabled by default and binds to 0.0.0.0:18789.',
93
+ references: [
94
+ 'https://github.com/Gitlawb/openclaude',
95
+ 'https://cybernews.com/security/anthropic-claude-code-source-leak/',
96
+ ],
97
+ },
98
+ {
99
+ name: 'openclaude-core',
100
+ versions: '*',
101
+ ecosystem: 'npm',
102
+ risk: 'leaked-source',
103
+ severity: 'high',
104
+ detail:
105
+ 'Core runtime package for openclaude. Derived from leaked Anthropic Claude Code ' +
106
+ 'source (March 2026). Under active DMCA enforcement.',
107
+ references: ['https://github.com/Gitlawb/openclaude'],
108
+ },
109
+
84
110
  // ---------------------------------------------------------------------------
85
111
  // License violations — well-known cases
86
112
  // ---------------------------------------------------------------------------