ship-safe 6.2.0 → 6.4.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 +41 -6
- package/cli/agents/agent-config-scanner.js +225 -1
- package/cli/agents/cicd-scanner.js +42 -0
- package/cli/agents/index.js +1 -0
- package/cli/agents/legal-risk-agent.js +328 -0
- package/cli/bin/ship-safe.js +23 -0
- package/cli/commands/audit.js +22 -2
- package/cli/commands/legal.js +158 -0
- package/cli/commands/scan-mcp.js +456 -0
- package/cli/commands/scan-skill.js +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,15 +11,16 @@
|
|
|
11
11
|
<a href="https://nodejs.org"><img src="https://img.shields.io/node/v/ship-safe" alt="Node.js version" /></a>
|
|
12
12
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
|
|
13
13
|
<a href="https://github.com/asamassekou10/ship-safe/stargazers"><img src="https://img.shields.io/github/stars/asamassekou10/ship-safe?style=social" alt="GitHub stars" /></a>
|
|
14
|
+
<a href="https://github.com/sponsors/asamassekou10"><img src="https://img.shields.io/badge/Sponsor-%E2%9D%A4-ea4aaa?logo=github" alt="Sponsor" /></a>
|
|
14
15
|
</p>
|
|
15
16
|
|
|
16
17
|
---
|
|
17
18
|
|
|
18
19
|
18 security agents. 80+ attack classes. One command.
|
|
19
20
|
|
|
20
|
-
**Ship Safe v6.
|
|
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.
|
|
21
22
|
|
|
22
|
-
**v6.
|
|
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.
|
|
23
24
|
|
|
24
25
|
[Documentation](https://shipsafecli.com/docs) | [Blog](https://shipsafecli.com/blog) | [Pricing](https://shipsafecli.com/pricing)
|
|
25
26
|
|
|
@@ -168,10 +169,10 @@ npx ship-safe audit .
|
|
|
168
169
|
| **PIIComplianceAgent** | Compliance | PII detection — SSNs, credit cards, emails, phone numbers in source code, logs, and configs |
|
|
169
170
|
| **VibeCodingAgent** | Code Vulns | AI-generated code patterns — no input validation, empty catch blocks, hardcoded secrets, disabled security features, TODO-auth patterns |
|
|
170
171
|
| **ExceptionHandlerAgent** | Code Vulns | OWASP A10:2025 — empty catch blocks, unhandled promise rejections, missing React error boundaries, leaked stack traces, generic catch-all without rethrow |
|
|
171
|
-
| **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 |
|
|
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, 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 |
|
|
172
173
|
| **MobileScanner** | Mobile | OWASP Mobile Top 10 2024 — insecure storage, WebView JS injection, HTTP endpoints, excessive permissions, debug mode |
|
|
173
174
|
| **GitHistoryScanner** | Secrets | Leaked secrets in git commit history (checks if still active in working tree) |
|
|
174
|
-
| **CICDScanner** | CI/CD | OWASP CI/CD Top 10 — pipeline poisoning, unpinned actions, secret logging, self-hosted runners, script injection |
|
|
175
|
+
| **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) |
|
|
175
176
|
| **APIFuzzer** | API | Routes without auth, missing input validation, mass assignment, unrestricted file upload, GraphQL introspection, debug endpoints, missing rate limiting, OpenAPI spec security issues |
|
|
176
177
|
| **ReconAgent** | Recon | Attack surface discovery — frameworks, languages, auth patterns, databases, cloud providers, IaC, CI/CD pipelines |
|
|
177
178
|
|
|
@@ -298,13 +299,13 @@ npx ship-safe audit . --verify
|
|
|
298
299
|
npx ship-safe doctor
|
|
299
300
|
```
|
|
300
301
|
|
|
301
|
-
###
|
|
302
|
+
### Agent Security
|
|
302
303
|
|
|
303
304
|
```bash
|
|
304
305
|
# Focused OpenClaw security scan
|
|
305
306
|
npx ship-safe openclaw .
|
|
306
307
|
|
|
307
|
-
# Auto-harden OpenClaw configs (0.0.0.0
|
|
308
|
+
# Auto-harden OpenClaw configs (0.0.0.0->127.0.0.1, add auth, ws->wss)
|
|
308
309
|
npx ship-safe openclaw . --fix
|
|
309
310
|
|
|
310
311
|
# Red team: simulate ClawJacked, prompt injection, data exfil attacks
|
|
@@ -318,6 +319,14 @@ npx ship-safe scan-skill https://clawhub.io/skills/some-skill
|
|
|
318
319
|
npx ship-safe scan-skill ./local-skill.json
|
|
319
320
|
npx ship-safe scan-skill --all # Scan all skills from openclaw.json
|
|
320
321
|
|
|
322
|
+
# Scan an MCP server's tool manifest before connecting
|
|
323
|
+
npx ship-safe scan-mcp https://your-mcp-server/
|
|
324
|
+
npx ship-safe scan-mcp ./local-manifest.json
|
|
325
|
+
npx ship-safe scan-mcp https://your-mcp-server/ --json
|
|
326
|
+
|
|
327
|
+
# Legal risk audit — DMCA, leaked-source derivatives (openclaude, claw-code-js), IP disputes
|
|
328
|
+
npx ship-safe legal .
|
|
329
|
+
|
|
321
330
|
# Generate hardened OpenClaw config
|
|
322
331
|
npx ship-safe init --openclaw
|
|
323
332
|
|
|
@@ -325,6 +334,20 @@ npx ship-safe init --openclaw
|
|
|
325
334
|
npx ship-safe abom .
|
|
326
335
|
```
|
|
327
336
|
|
|
337
|
+
#### openclaude and claw-code
|
|
338
|
+
|
|
339
|
+
Ship Safe detects security issues in both major Claude Code forks from the March 2026 source leak.
|
|
340
|
+
|
|
341
|
+
**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:
|
|
342
|
+
- `OPENAI_BASE_URL` using `http://` for non-localhost endpoints (unencrypted LLM traffic)
|
|
343
|
+
- The profile file present in a project not covered by `.gitignore` (API key exposure risk)
|
|
344
|
+
|
|
345
|
+
**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:
|
|
346
|
+
- `permissionMode: danger-full-access` or `dangerouslySkipPermissions: true` (no confirmation on any tool call)
|
|
347
|
+
- `sandbox.enabled: false` (filesystem isolation removed)
|
|
348
|
+
- Hook commands containing shell execution or remote download patterns
|
|
349
|
+
- MCP server connections over `ws://` or `http://` to non-localhost hosts
|
|
350
|
+
|
|
328
351
|
### Threat Intelligence
|
|
329
352
|
|
|
330
353
|
```bash
|
|
@@ -720,6 +743,18 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
|
720
743
|
|
|
721
744
|
---
|
|
722
745
|
|
|
746
|
+
## Sponsors
|
|
747
|
+
|
|
748
|
+
Ship Safe is MIT-licensed and free forever. If it saves you time or helps you ship more securely, consider sponsoring — it helps keep the project maintained and growing.
|
|
749
|
+
|
|
750
|
+
<p align="center">
|
|
751
|
+
<a href="https://github.com/sponsors/asamassekou10">
|
|
752
|
+
<img src="https://img.shields.io/badge/Sponsor%20Ship%20Safe-%E2%9D%A4-ea4aaa?style=for-the-badge&logo=github" alt="Sponsor Ship Safe" />
|
|
753
|
+
</a>
|
|
754
|
+
</p>
|
|
755
|
+
|
|
756
|
+
---
|
|
757
|
+
|
|
723
758
|
## License
|
|
724
759
|
|
|
725
760
|
MIT - Use it, share it, secure your stuff.
|
|
@@ -54,6 +54,32 @@ const OPENCLAW_GLOBS = [
|
|
|
54
54
|
'.openclaw/**/*.json',
|
|
55
55
|
];
|
|
56
56
|
|
|
57
|
+
// openclaude (github.com/Gitlawb/openclaude) — Claude Code fork with
|
|
58
|
+
// OpenAI-compatible provider shim. Config is purely via environment variables
|
|
59
|
+
// (CLAUDE_CODE_USE_OPENAI, OPENAI_BASE_URL, OPENAI_MODEL, OPENAI_API_KEY).
|
|
60
|
+
// The only persistent file artifact is .openclaude-profile.json, which stores
|
|
61
|
+
// named profiles as { name, env: { OPENAI_BASE_URL, OPENAI_API_KEY, ... } }.
|
|
62
|
+
const OPENCLAUDE_PROFILE_FILES = [
|
|
63
|
+
'.openclaude-profile.json',
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
// claw-code (github.com/instructkr/claw-code, now ultraworkers/claw-code) —
|
|
67
|
+
// Rust + Python clean-room rewrite of Claude Code's agent harness.
|
|
68
|
+
// CLI tool (`claw` binary). NOT a server — no port binding outside tests.
|
|
69
|
+
// Config files: .claw.json (project root), .claw/settings.json,
|
|
70
|
+
// .claw/settings.local.json, ~/.claw.json, ~/.claw/settings.json
|
|
71
|
+
// Auth: ANTHROPIC_API_KEY, OPENAI_API_KEY, or XAI_API_KEY env vars.
|
|
72
|
+
// Permission modes: read-only, workspace-write, danger-full-access, prompt, allow.
|
|
73
|
+
// --dangerously-skip-permissions flag disables all permission checks.
|
|
74
|
+
// Sandbox: SandboxConfig with FilesystemIsolationMode (workspace-only default).
|
|
75
|
+
// Hooks: preToolUse / postToolUse arrays in settings JSON.
|
|
76
|
+
// MCP: mcpServers in settings JSON (stdio, sse, http, ws transports).
|
|
77
|
+
const CLAW_CODE_FILES = [
|
|
78
|
+
'.claw.json',
|
|
79
|
+
'.claw/settings.json',
|
|
80
|
+
'.claw/settings.local.json',
|
|
81
|
+
];
|
|
82
|
+
|
|
57
83
|
const MEMORY_GLOBS = [
|
|
58
84
|
'.claude/memory/**',
|
|
59
85
|
'.cursor/memory/**',
|
|
@@ -230,6 +256,18 @@ export class AgentConfigScanner extends BaseAgent {
|
|
|
230
256
|
findings = findings.concat(this._scanOpenClawConfig(file));
|
|
231
257
|
}
|
|
232
258
|
|
|
259
|
+
// ── 3b. Scan openclaude profile files ─────────────────────────────────
|
|
260
|
+
for (const file of discovered.openclaudeFiles) {
|
|
261
|
+
findings = findings.concat(this.scanFileWithPatterns(file, PATTERNS));
|
|
262
|
+
findings = findings.concat(this._scanOpenClaudeProfile(file));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ── 3c. Scan claw-code config files ────────────────────────────────────
|
|
266
|
+
for (const file of discovered.clawCodeFiles) {
|
|
267
|
+
findings = findings.concat(this.scanFileWithPatterns(file, PATTERNS));
|
|
268
|
+
findings = findings.concat(this._scanClawCodeConfig(file));
|
|
269
|
+
}
|
|
270
|
+
|
|
233
271
|
// ── 4. Scan Claude Code hooks ──────────────────────────────────────────
|
|
234
272
|
for (const file of discovered.claudeSettingsFiles) {
|
|
235
273
|
findings = findings.concat(this._scanClaudeHooks(file));
|
|
@@ -297,7 +335,21 @@ export class AgentConfigScanner extends BaseAgent {
|
|
|
297
335
|
memoryFiles.push(...globbed);
|
|
298
336
|
} catch { /* skip */ }
|
|
299
337
|
|
|
300
|
-
|
|
338
|
+
// ── openclaude profile files ─────────────────────────────────────────────
|
|
339
|
+
const openclaudeFiles = [];
|
|
340
|
+
for (const rel of OPENCLAUDE_PROFILE_FILES) {
|
|
341
|
+
const full = path.join(rootPath, rel);
|
|
342
|
+
if (fs.existsSync(full)) openclaudeFiles.push(full);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ── claw-code config files ────────────────────────────────────────────────
|
|
346
|
+
const clawCodeFiles = [];
|
|
347
|
+
for (const rel of CLAW_CODE_FILES) {
|
|
348
|
+
const full = path.join(rootPath, rel);
|
|
349
|
+
if (fs.existsSync(full)) clawCodeFiles.push(full);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return { rulesFiles, openclawFiles, openclaudeFiles, clawCodeFiles, claudeSettingsFiles, memoryFiles };
|
|
301
353
|
}
|
|
302
354
|
|
|
303
355
|
// ===========================================================================
|
|
@@ -415,6 +467,178 @@ export class AgentConfigScanner extends BaseAgent {
|
|
|
415
467
|
return findings;
|
|
416
468
|
}
|
|
417
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Scan .openclaude-profile.json for security issues.
|
|
472
|
+
*
|
|
473
|
+
* openclaude (github.com/Gitlawb/openclaude) is a CLI tool, not a server.
|
|
474
|
+
* There is no config file, no host/port binding, no auth mechanism.
|
|
475
|
+
* All configuration is via environment variables:
|
|
476
|
+
* CLAUDE_CODE_USE_OPENAI=1, OPENAI_BASE_URL, OPENAI_MODEL, OPENAI_API_KEY
|
|
477
|
+
*
|
|
478
|
+
* The only persistent file artifact is .openclaude-profile.json, which stores
|
|
479
|
+
* named profiles as { name: string, env: { OPENAI_BASE_URL, OPENAI_API_KEY, ... } }.
|
|
480
|
+
* openclaude ships with this file in its default .gitignore.
|
|
481
|
+
*
|
|
482
|
+
* Security risk: if OPENAI_BASE_URL is an http:// (non-TLS) endpoint, all
|
|
483
|
+
* LLM traffic (prompts, code context, responses) is sent unencrypted.
|
|
484
|
+
*/
|
|
485
|
+
_scanOpenClaudeProfile(filePath) {
|
|
486
|
+
const content = this.readFile(filePath);
|
|
487
|
+
if (!content) return [];
|
|
488
|
+
const findings = [];
|
|
489
|
+
|
|
490
|
+
let profile;
|
|
491
|
+
try { profile = JSON.parse(content); } catch { return []; }
|
|
492
|
+
|
|
493
|
+
const env = profile.env || {};
|
|
494
|
+
|
|
495
|
+
// ── Insecure provider URL (http:// for non-localhost) ─────────────────
|
|
496
|
+
const baseUrl = env.OPENAI_BASE_URL || '';
|
|
497
|
+
if (baseUrl && /^http:\/\/(?!localhost|127\.0\.0\.1|::1)/i.test(baseUrl)) {
|
|
498
|
+
findings.push(createFinding({
|
|
499
|
+
file: filePath, line: 1,
|
|
500
|
+
severity: 'high',
|
|
501
|
+
category: this.category,
|
|
502
|
+
rule: 'OPENCLAUDE_INSECURE_PROVIDER_URL',
|
|
503
|
+
title: 'openclaude: LLM Provider URL Without TLS',
|
|
504
|
+
description:
|
|
505
|
+
`openclaude routes model calls to ${baseUrl} over plain HTTP. ` +
|
|
506
|
+
'Prompts, code context, and model responses are sent unencrypted. ' +
|
|
507
|
+
'A network attacker can read or modify all LLM interactions in transit.',
|
|
508
|
+
matched: `OPENAI_BASE_URL: "${baseUrl}"`,
|
|
509
|
+
confidence: 'high',
|
|
510
|
+
cwe: 'CWE-319',
|
|
511
|
+
owasp: 'A02:2021',
|
|
512
|
+
fix: 'Use an https:// provider URL. Never route LLM traffic over plaintext HTTP on untrusted networks.',
|
|
513
|
+
}));
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return findings;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Scan claw-code config files (.claw.json, .claw/settings.json, .claw/settings.local.json)
|
|
521
|
+
* for insecure settings.
|
|
522
|
+
*
|
|
523
|
+
* claw-code (ultraworkers/claw-code) is a Rust + Python clean-room rewrite of Claude Code.
|
|
524
|
+
* It is a CLI tool — no server port binding. Config lives in JSON settings files.
|
|
525
|
+
*
|
|
526
|
+
* Checked settings:
|
|
527
|
+
* - hooks.preToolUse / hooks.postToolUse: shell hook commands (RCE vector)
|
|
528
|
+
* - permissions.dangerouslySkipPermissions / permissionMode: "danger-full-access"
|
|
529
|
+
* - sandbox.enabled: false (filesystem isolation disabled)
|
|
530
|
+
* - mcpServers with insecure ws:// or http:// remote URLs (MiTM risk)
|
|
531
|
+
* - mcpServers using env vars that could expose credentials
|
|
532
|
+
*/
|
|
533
|
+
_scanClawCodeConfig(filePath) {
|
|
534
|
+
const content = this.readFile(filePath);
|
|
535
|
+
if (!content) return [];
|
|
536
|
+
const findings = [];
|
|
537
|
+
|
|
538
|
+
let config;
|
|
539
|
+
try { config = JSON.parse(content); } catch { return []; }
|
|
540
|
+
|
|
541
|
+
// ── Dangerous permission mode ─────────────────────────────────────────
|
|
542
|
+
const permMode = config.permissionMode ?? config.permissions?.mode ?? '';
|
|
543
|
+
const skipPerms = config.dangerouslySkipPermissions ??
|
|
544
|
+
config.permissions?.dangerouslySkipPermissions ?? false;
|
|
545
|
+
|
|
546
|
+
if (skipPerms === true || permMode === 'danger-full-access') {
|
|
547
|
+
findings.push(createFinding({
|
|
548
|
+
file: filePath, line: 1,
|
|
549
|
+
severity: 'high',
|
|
550
|
+
category: this.category,
|
|
551
|
+
rule: 'CLAW_CODE_SKIP_PERMISSIONS',
|
|
552
|
+
title: 'claw-code: All Permission Checks Disabled',
|
|
553
|
+
description:
|
|
554
|
+
'claw-code is configured with dangerously-skip-permissions or permissionMode: danger-full-access. ' +
|
|
555
|
+
'Every tool call executes without asking for user confirmation. ' +
|
|
556
|
+
'A single prompt injection in any file the agent reads can trigger unrestricted shell execution or file writes.',
|
|
557
|
+
matched: skipPerms ? 'dangerouslySkipPermissions: true' : `permissionMode: "${permMode}"`,
|
|
558
|
+
confidence: 'high',
|
|
559
|
+
cwe: 'CWE-269',
|
|
560
|
+
owasp: 'ASI03',
|
|
561
|
+
fix: 'Set permissionMode to "workspace-write" or "prompt". Only use danger-full-access in fully isolated environments.',
|
|
562
|
+
}));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// ── Sandbox disabled ──────────────────────────────────────────────────
|
|
566
|
+
if (config.sandbox?.enabled === false) {
|
|
567
|
+
findings.push(createFinding({
|
|
568
|
+
file: filePath, line: 1,
|
|
569
|
+
severity: 'medium',
|
|
570
|
+
category: this.category,
|
|
571
|
+
rule: 'CLAW_CODE_SANDBOX_DISABLED',
|
|
572
|
+
title: 'claw-code: Filesystem Sandbox Disabled',
|
|
573
|
+
description:
|
|
574
|
+
'claw-code sandbox is explicitly disabled. By default claw-code restricts ' +
|
|
575
|
+
'filesystem access to the workspace directory. With sandbox off, tools can ' +
|
|
576
|
+
'read and write anywhere on the system.',
|
|
577
|
+
matched: 'sandbox.enabled: false',
|
|
578
|
+
confidence: 'high',
|
|
579
|
+
cwe: 'CWE-732',
|
|
580
|
+
owasp: 'ASI03',
|
|
581
|
+
fix: 'Remove sandbox.enabled: false or set filesystem-mode to workspace-only.',
|
|
582
|
+
}));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// ── Hooks with shell commands ──────────────────────────────────────────
|
|
586
|
+
const hookLists = [
|
|
587
|
+
...(config.hooks?.preToolUse || []),
|
|
588
|
+
...(config.hooks?.postToolUse || []),
|
|
589
|
+
];
|
|
590
|
+
for (const hook of hookLists) {
|
|
591
|
+
const cmd = typeof hook === 'string' ? hook : (hook.command || hook.cmd || hook.run || '');
|
|
592
|
+
if (!cmd) continue;
|
|
593
|
+
if (/(?:bash\s+-c|sh\s+-c|cmd\s+\/c|powershell\s+-|pwsh\s+-)/i.test(cmd) ||
|
|
594
|
+
/\|\s*(?:bash|sh|zsh|node|python)/i.test(cmd) ||
|
|
595
|
+
/(?:curl|wget)\s+https?:\/\/(?!localhost|127\.0\.0\.1)/i.test(cmd)) {
|
|
596
|
+
findings.push(createFinding({
|
|
597
|
+
file: filePath, line: 1,
|
|
598
|
+
severity: 'critical',
|
|
599
|
+
category: this.category,
|
|
600
|
+
rule: 'CLAW_CODE_HOOK_SHELL',
|
|
601
|
+
title: 'claw-code: Dangerous Hook Command',
|
|
602
|
+
description:
|
|
603
|
+
'claw-code hook contains a shell execution or remote download command. ' +
|
|
604
|
+
'A malicious .claw.json in a repository can achieve RCE when anyone ' +
|
|
605
|
+
'opens the project with claw.',
|
|
606
|
+
matched: cmd.substring(0, 150),
|
|
607
|
+
confidence: 'high',
|
|
608
|
+
cwe: 'CWE-94',
|
|
609
|
+
owasp: 'ASI04',
|
|
610
|
+
fix: 'Remove shell execution hooks. Use only safe, scoped commands in claw hooks.',
|
|
611
|
+
}));
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// ── MCP servers with insecure remote URLs ─────────────────────────────
|
|
616
|
+
const mcpServers = config.mcpServers || {};
|
|
617
|
+
for (const [name, srv] of Object.entries(mcpServers)) {
|
|
618
|
+
const url = typeof srv === 'object' ? (srv.url || '') : '';
|
|
619
|
+
if (/^(?:ws|http):\/\/(?!localhost|127\.0\.0\.1|::1)/i.test(url)) {
|
|
620
|
+
findings.push(createFinding({
|
|
621
|
+
file: filePath, line: 1,
|
|
622
|
+
severity: 'high',
|
|
623
|
+
category: this.category,
|
|
624
|
+
rule: 'CLAW_CODE_MCP_INSECURE_URL',
|
|
625
|
+
title: `claw-code: MCP Server "${name}" Uses Unencrypted Transport`,
|
|
626
|
+
description:
|
|
627
|
+
`MCP server "${name}" connects to ${url} over an unencrypted channel (ws:// or http://). ` +
|
|
628
|
+
'All MCP messages — tool calls, results, and any code context — are sent in plaintext. ' +
|
|
629
|
+
'A network attacker can intercept or inject MCP responses to hijack the agent.',
|
|
630
|
+
matched: url,
|
|
631
|
+
confidence: 'high',
|
|
632
|
+
cwe: 'CWE-319',
|
|
633
|
+
owasp: 'A02:2021',
|
|
634
|
+
fix: 'Use wss:// or https:// for all non-localhost MCP server connections.',
|
|
635
|
+
}));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return findings;
|
|
640
|
+
}
|
|
641
|
+
|
|
418
642
|
/**
|
|
419
643
|
* Scan .claude/settings.json for malicious hooks.
|
|
420
644
|
* 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 {
|
package/cli/agents/index.js
CHANGED
|
@@ -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 { LegalRiskAgent, LEGALLY_RISKY_PACKAGES } from './legal-risk-agent.js';
|
|
29
30
|
export { ABOMGenerator } from './abom-generator.js';
|
|
30
31
|
export { VerifierAgent } from './verifier-agent.js';
|
|
31
32
|
export { DeepAnalyzer } from './deep-analyzer.js';
|