ship-safe 7.0.0 → 8.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
@@ -16,11 +16,11 @@
16
16
 
17
17
  ---
18
18
 
19
- 18 security agents. 80+ attack classes. One command.
19
+ 22 security agents. 80+ attack classes. One command.
20
20
 
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
+ **Ship Safe v8.0.0** is an AI-powered security platform that runs 22 specialized agents in parallel against your codebase covering secrets, injection vulnerabilities, auth bypass, SSRF, supply chain attacks, memory poisoning, Hermes Agent security, Supabase RLS, Docker/Terraform/Kubernetes misconfigs, CI/CD pipeline poisoning, LLM/agentic AI security, MCP server misuse, RAG poisoning, PII compliance, vibe coding patterns, exception handling, Claude Managed Agent configs, and more. Full OWASP Agentic AI Top 10 mapping (ASI-01–ASI-10) enriches every finding. Live OSV.dev advisory feed surfaces actively exploited CVEs within hours of disclosure. 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.
22
22
 
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
+ **v8.0.0 highlights:** **Ship Safe × Hermes Agent** — two new agents purpose-built for [NousResearch Hermes Agent](https://github.com/NousResearch/hermes-function-calling) deployments. `HermesSecurityAgent` detects 17 attack patterns across the full OWASP Agentic AI Top 10 surface: tool registry poisoning, function-call injection, goal/plan hijacking, memory layer attacks, skill permission drift, and multi-agent trust boundary violations. `AgentAttestationAgent` catches supply-chain failures in agent manifests: unpinned versions, missing integrity hashes on remote tool sources, unsigned manifests, and dynamic `require()` of manifests from env vars. Both agents integrate into the `--agentic` loop for automated scan annotate re-scan cycles. Ship Safe is now a first-class Hermes citizen via `skills/ship-safe-security.md` and `registerWithHermes()`.
24
24
 
25
25
  [Documentation](https://shipsafecli.com/docs) | [Blog](https://shipsafecli.com/blog) | [Pricing](https://shipsafecli.com/pricing)
26
26
 
@@ -29,19 +29,32 @@
29
29
  ## Quick Start
30
30
 
31
31
  ```bash
32
- # Full security audit — secrets + 18 agents + deps + remediation plan
32
+ # Full security audit — secrets + 22 agents + deps + remediation plan
33
33
  npx ship-safe audit .
34
34
 
35
- # LLM-powered deep analysis (Anthropic, OpenAI, Google, Ollama)
35
+ # LLM-powered deep analysis (Anthropic, OpenAI, Google, Ollama, Gemma 4)
36
36
  npx ship-safe audit . --deep
37
37
 
38
- # Red team scan only (18 agents, 80+ attack classes)
38
+ # Agentic loop scan auto-annotate fixes re-scan until score ≥ 75
39
+ npx ship-safe audit . --agentic
40
+ npx ship-safe audit . --agentic 5 --agentic-target 85
41
+
42
+ # Red team scan (22 agents, 80+ attack classes)
39
43
  npx ship-safe red-team .
40
44
 
41
45
  # Scan only changed files (fast pre-commit & PR scanning)
42
46
  npx ship-safe diff
43
47
  npx ship-safe diff --staged
44
48
 
49
+ # Live OSV.dev advisory feed — no API key, no stale data
50
+ npx ship-safe advisories .
51
+
52
+ # Continuous monitoring
53
+ npx ship-safe watch . # Lightweight file watcher
54
+ npx ship-safe watch . --deep # Full 22-agent scan on every change
55
+ npx ship-safe watch . --deep --threshold 80 # Fail if score drops below threshold
56
+ npx ship-safe watch . --status # Show last deep-watch results
57
+
45
58
  # Fun emoji security grade with shareable badge
46
59
  npx ship-safe vibe-check .
47
60
 
@@ -86,11 +99,11 @@ npx ship-safe audit .
86
99
 
87
100
  ```
88
101
  ════════════════════════════════════════════════════════════
89
- Ship Safe v6.0 — Full Security Audit
102
+ Ship Safe v8.0 — Full Security Audit
90
103
  ════════════════════════════════════════════════════════════
91
104
 
92
105
  [Phase 1/4] Scanning for secrets... ✔ 49 found
93
- [Phase 2/4] Running 18 security agents... ✔ 103 findings
106
+ [Phase 2/4] Running 22 security agents... ✔ 103 findings
94
107
  [Phase 3/4] Auditing dependencies... ✔ 44 CVEs
95
108
  [Phase 4/4] Computing security score... ✔ 25/100 F
96
109
 
@@ -117,7 +130,7 @@ npx ship-safe audit .
117
130
 
118
131
  **What it runs:**
119
132
  1. **Secret scan** — 50+ patterns with entropy scoring (API keys, passwords, tokens)
120
- 2. **18 security agents** — run in parallel with per-agent timeouts and framework-aware filtering (injection, auth, SSRF, supply chain, config, Supabase RLS, LLM, MCP, agentic AI, RAG, PII, vibe coding, exception handling, agent config, mobile, git history, CI/CD, API)
133
+ 2. **22 security agents** — run in parallel with per-agent timeouts and framework-aware filtering
121
134
  3. **Dependency audit** — npm/pip/bundler CVE scanning with EPSS exploit probability scores
122
135
  4. **Secrets verification** — probes provider APIs (GitHub, Stripe, OpenAI, etc.) to check if leaked keys are still active
123
136
  5. **Deep analysis** — LLM-powered taint analysis verifies exploitability of critical/high findings (optional)
@@ -143,38 +156,43 @@ npx ship-safe audit .
143
156
  - `--deep` — LLM-powered taint analysis for critical/high findings
144
157
  - `--local` — use local Ollama model for deep analysis
145
158
  - `--model <model>` — LLM model to use for deep/AI analysis
146
- - `--provider <name>` — LLM provider: groq, together, mistral, deepseek, xai, perplexity, lmstudio
159
+ - `--provider <name>` — LLM provider: groq, together, mistral, deepseek, xai, perplexity, lmstudio, gemma4
147
160
  - `--base-url <url>` — custom OpenAI-compatible base URL (e.g. LM Studio, vLLM)
148
161
  - `--budget <cents>` — max spend in cents for deep analysis (default: 50)
149
162
  - `--verify` — check if leaked secrets are still active (probes provider APIs)
163
+ - `--agentic [n]` — scan → annotate fixes → re-scan loop, up to n iterations (default: 3)
164
+ - `--agentic-target <score>` — stop agentic loop when score reaches this threshold (default: 75)
150
165
 
151
166
  ---
152
167
 
153
- ## 18 Security Agents
168
+ ## 22 Security Agents
154
169
 
155
170
  | Agent | Category | What It Detects |
156
171
  |-------|----------|-----------------|
157
172
  | **InjectionTester** | Code Vulns | SQL/NoSQL injection, command injection, code injection (eval), XSS, path traversal, XXE, ReDoS, prototype pollution, Python f-string SQL injection, Python subprocess shell injection |
158
173
  | **AuthBypassAgent** | Auth | JWT vulnerabilities (alg:none, weak secrets), cookie security, CSRF, OAuth misconfig, BOLA/IDOR, weak crypto, timing attacks, TLS bypass, Django `DEBUG = True`, Flask hardcoded secret keys |
159
174
  | **SSRFProber** | SSRF | User input in fetch/axios, cloud metadata endpoints, internal IPs, redirect following |
160
- | **SupplyChainAudit** | Supply Chain | Typosquatting (Levenshtein distance), git/URL dependencies, wildcard versions, suspicious install scripts, dependency confusion, lockfile integrity |
175
+ | **SupplyChainAudit** | Supply Chain | Typosquatting (Levenshtein distance), git/URL dependencies, wildcard versions, suspicious install scripts, dependency confusion, lockfile integrity, trojanized package behavioral signatures (env-var harvesting, DNS exfiltration, WebSocket C2) |
161
176
  | **ConfigAuditor** | Config | Dockerfile (running as root, :latest tags), Terraform (public S3/RDS, open SG, CloudFront HTTP, Lambda admin, S3 no versioning), Kubernetes (privileged containers, `:latest` tags, missing NetworkPolicy), CORS, CSP, Firebase, Nginx |
162
177
  | **SupabaseRLSAgent** | Auth | Supabase Row Level Security — `service_role` key in client code, `CREATE TABLE` without RLS, anon key inserts, unprotected storage operations |
163
178
  | **LLMRedTeam** | AI/LLM | OWASP LLM Top 10 — prompt injection, excessive agency, system prompt leakage, unbounded consumption, RAG poisoning |
164
179
  | **MCPSecurityAgent** | AI/LLM | MCP server security — unvalidated tool inputs, missing auth, excessive permissions, tool poisoning, typosquatting detection, over-permissioned tools, shadow config discovery |
165
180
  | **AgenticSecurityAgent** | AI/LLM | OWASP Agentic AI Top 10 — agent hijacking, privilege escalation, unsafe code execution, memory poisoning |
166
181
  | **RAGSecurityAgent** | AI/LLM | RAG pipeline security — unvalidated embeddings, context injection, document poisoning, vector DB access control |
182
+ | **MemoryPoisoningAgent** | AI/LLM | ASI-01/ASI-05 — instruction injection in `.claude/memory/`, `.cursorrules`, `.cursor/rules/`, `.windsurfrules`, `.continue/config.json`, `.gemini/`, `.cody/`, `.augment/` and docs; hidden Unicode payloads; persona hijacking; persistent trigger detection |
167
183
  | **PIIComplianceAgent** | Compliance | PII detection — SSNs, credit cards, emails, phone numbers in source code, logs, and configs |
168
184
  | **VibeCodingAgent** | Code Vulns | AI-generated code patterns — no input validation, empty catch blocks, hardcoded secrets, disabled security features, TODO-auth patterns |
169
185
  | **ExceptionHandlerAgent** | Code Vulns | OWASP A10:2025 — empty catch blocks, unhandled promise rejections, missing React error boundaries, leaked stack traces, generic catch-all without rethrow |
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 |
186
+ | **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, claw-code config risks, Gemini CLI / Cody / Augment Code config risks, encoded/obfuscated payloads |
171
187
  | **MobileScanner** | Mobile | OWASP Mobile Top 10 2024 — insecure storage, WebView JS injection, HTTP endpoints, excessive permissions, debug mode |
172
188
  | **GitHistoryScanner** | Secrets | Leaked secrets in git commit history (checks if still active in working tree) |
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) |
189
+ | **CICDScanner** | CI/CD | OWASP CI/CD Top 10 — pipeline poisoning, unpinned actions, secret logging, self-hosted runners, script injection, AI agent danger flags |
174
190
  | **APIFuzzer** | API | Routes without auth, missing input validation, mass assignment, unrestricted file upload, GraphQL introspection, debug endpoints, missing rate limiting, OpenAPI spec security issues |
175
- | **ReconAgent** | Recon | Attack surface discoveryframeworks, languages, auth patterns, databases, cloud providers, IaC, CI/CD pipelines |
191
+ | **ManagedAgentScanner** | AI/LLM | Claude Managed Agents misconfigurations `always_allow` permission policies, unrestricted networking, bash without human confirmation, MCP servers over HTTP, hardcoded vault tokens, unpinned environment packages (ASI-03, ASI-04, ASI-05, ASI-07) |
192
+ | **HermesSecurityAgent** *(new)* | AI/LLM | Hermes Agent deployments — tool registry poisoning, function-call injection (`<tool_call>` / `<function_calls>`), goal/plan hijacking, memory layer attacks, skill permission drift, sub-agent trust boundary violations, manifest attestation (ASI-01–ASI-10) |
193
+ | **AgentAttestationAgent** *(new)* | Supply Chain | Agent manifest supply chain — unpinned versions (`latest`, `^`, `~`), missing integrity hashes on remote tool sources, unsigned manifests, `skipIntegrityCheck` bypass, dynamic `require()` of manifests from env vars, missing provenance fields (ASI-10, SLSA Level 0) |
176
194
 
177
- **Post-processors:** ScoringEngine (8-category weighted scoring), VerifierAgent (secrets liveness verification), DeepAnalyzer (LLM-powered taint analysis)
195
+ **Post-processors:** ScoringEngine (8-category weighted scoring with OWASP Agentic AI Top 10 enrichment), VerifierAgent (secrets liveness verification), DeepAnalyzer (LLM-powered taint analysis)
178
196
 
179
197
  ---
180
198
 
@@ -186,7 +204,7 @@ npx ship-safe audit .
186
204
  # Full audit with remediation plan + HTML report
187
205
  npx ship-safe audit .
188
206
 
189
- # Red team: 18 agents, 80+ attack classes
207
+ # Red team: 22 agents, 80+ attack classes
190
208
  npx ship-safe red-team .
191
209
  npx ship-safe red-team . --agents injection,auth # Run specific agents
192
210
  npx ship-safe red-team . --html report.html # HTML report
@@ -346,6 +364,27 @@ Ship Safe detects security issues in both major Claude Code forks from the March
346
364
  - Hook commands containing shell execution or remote download patterns
347
365
  - MCP server connections over `ws://` or `http://` to non-localhost hosts
348
366
 
367
+ ### Hermes Agent Integration
368
+
369
+ Ship Safe is a first-class Hermes Agent citizen. Register Ship Safe tools directly in your Hermes tool registry:
370
+
371
+ ```js
372
+ import { registerWithHermes, verifyIntegrity } from 'ship-safe';
373
+
374
+ // Register all 5 Ship Safe tools with integrity verification
375
+ await registerWithHermes(toolRegistry);
376
+ ```
377
+
378
+ Or use the bundled skill in your Hermes agent:
379
+
380
+ ```yaml
381
+ # In your Hermes agent manifest
382
+ skills:
383
+ - ./node_modules/ship-safe/skills/ship-safe-security.md
384
+ ```
385
+
386
+ Available tools: `ship_safe_audit`, `ship_safe_scan_mcp`, `ship_safe_get_findings`, `ship_safe_suppress_finding`, `ship_safe_memory_list`.
387
+
349
388
  ### Threat Intelligence
350
389
 
351
390
  ```bash
@@ -396,6 +435,16 @@ jobs:
396
435
 
397
436
  Scans `openclaw.json`, `.cursorrules`, `CLAUDE.md`, Claude Code hooks, and MCP configs. Checks against the bundled threat intelligence database for known ClawHavoc IOCs.
398
437
 
438
+ ### Live Advisory Feed
439
+
440
+ ```bash
441
+ # Query OSV.dev for actively exploited CVEs across all package ecosystems
442
+ npx ship-safe advisories .
443
+ npx ship-safe advisories . --json # JSON output for CI
444
+ ```
445
+
446
+ No API key required. Malware advisories (MAL-*) are sorted to the top. Results include EPSS exploit probability and remediation guidance.
447
+
399
448
  ### Defensive Hooks
400
449
 
401
450
  ```bash
@@ -409,9 +458,15 @@ npx ship-safe watch . --configs
409
458
  ### Infrastructure Commands
410
459
 
411
460
  ```bash
412
- # Continuous monitoring (watch files for changes)
461
+ # Lightweight file watcher — re-scans changed files on save
413
462
  npx ship-safe watch .
414
463
 
464
+ # Deep watch — full 22-agent orchestrator on every change
465
+ npx ship-safe watch . --deep
466
+ npx ship-safe watch . --deep --threshold 80 # Fail if score drops below threshold
467
+ npx ship-safe watch . --deep --debounce 2000 # Custom debounce in ms (default: 1000)
468
+ npx ship-safe watch . --status # Show last deep-watch results from .ship-safe/watch.json
469
+
415
470
  # Generate CycloneDX SBOM
416
471
  npx ship-safe sbom .
417
472
 
@@ -467,7 +522,7 @@ claude plugin add github:asamassekou10/ship-safe
467
522
 
468
523
  | Command | Description |
469
524
  |---------|-------------|
470
- | `/ship-safe` | Full security audit — 18 agents, remediation plan, auto-fix |
525
+ | `/ship-safe` | Full security audit — 22 agents, remediation plan, auto-fix |
471
526
  | `/ship-safe-scan` | Quick scan for leaked secrets |
472
527
  | `/ship-safe-score` | Security health score (0-100) |
473
528
  | `/ship-safe-deep` | LLM-powered deep taint analysis |
@@ -524,7 +579,8 @@ Ship Safe supports any AI provider for deep analysis and classification:
524
579
  | **Anthropic** | `ANTHROPIC_API_KEY` | *(auto-detected)* | claude-haiku-4-5 |
525
580
  | **OpenAI** | `OPENAI_API_KEY` | *(auto-detected)* | gpt-4o-mini |
526
581
  | **Google** | `GOOGLE_AI_API_KEY` | *(auto-detected)* | gemini-2.0-flash |
527
- | **Ollama** | `OLLAMA_HOST` | `--local` | Local models |
582
+ | **Gemma 4 (Ollama)** | *(none)* | `--provider gemma4` | gemma4:e4b (256K ctx) |
583
+ | **Ollama** | `OLLAMA_HOST` | `--local` | gemma4:e4b |
528
584
  | **Groq** | `GROQ_API_KEY` | `--provider groq` | llama-3.3-70b-versatile |
529
585
  | **Together AI** | `TOGETHER_API_KEY` | `--provider together` | meta-llama/Llama-3-70b-chat-hf |
530
586
  | **Mistral** | `MISTRAL_API_KEY` | `--provider mistral` | mistral-small-latest |
@@ -656,7 +712,7 @@ docs/
656
712
  | **OWASP Top 10 Mobile 2024** | M1-M10: Improper Credential Usage, Inadequate Supply Chain, Insecure Auth, Insufficient Validation, Insecure Communication, Inadequate Privacy, Binary Protections, Security Misconfiguration, Insecure Data Storage, Insufficient Cryptography |
657
713
  | **OWASP LLM Top 10 2025** | LLM01-LLM10: Prompt Injection, Sensitive Info Disclosure, Supply Chain, Data Poisoning, Improper Output Handling, Excessive Agency, System Prompt Leakage, Vector/Embedding Weaknesses, Misinformation, Unbounded Consumption |
658
714
  | **OWASP CI/CD Top 10** | CICD-SEC-1 to 10: Insufficient Flow Control, Identity Management, Dependency Chain Abuse, Poisoned Pipeline Execution, Insufficient PBAC, Credential Hygiene, Insecure System Config, Ungoverned Usage, Improper Artifact Integrity, Insufficient Logging |
659
- | **OWASP Agentic AI Top 10** | ASI01-ASI10: Agent Hijacking, Tool Misuse, Privilege Escalation, Unsafe Code Execution, Memory Poisoning, Identity Spoofing, Excessive Autonomy, Logging Gaps, Supply Chain Attacks, Cascading Hallucination |
715
+ | **OWASP Agentic AI Top 10** | ASI-01–ASI-10: Goal Hijacking, Excessive Agency, Unsafe Tool Use, Unvalidated Actions, Untrusted Tools, Memory Poisoning, Lack of Oversight, Logging Gaps, Supply Chain Attacks, Cascading Failures |
660
716
 
661
717
  ---
662
718
 
@@ -674,6 +730,9 @@ LLM security: prompt injection detection, cost protection, system prompt hardeni
674
730
  ### [`/checklists`](./checklists)
675
731
  Manual security audits: launch-day checklist, framework-specific guides.
676
732
 
733
+ ### [`/skills`](./skills)
734
+ Hermes Agent skill definitions. Install `skills/ship-safe-security.md` to give any Hermes agent native security scanning capabilities.
735
+
677
736
  ---
678
737
 
679
738
  ## Add a Security Badge to Your README
@@ -0,0 +1,318 @@
1
+ /**
2
+ * AgentAttestationAgent — Ship Safe × Hermes Agent
3
+ * ==================================================
4
+ *
5
+ * Detects missing or broken attestation in agent manifests and deployment
6
+ * configurations: unsigned manifests, missing provenance, unpinned package
7
+ * versions, integrity hash drift, and lack of supply-chain controls.
8
+ *
9
+ * OWASP Agentic AI: ASI-10 (Supply Chain), ASI-07 (Lack of Oversight)
10
+ * SLSA Level 0 → checking for basic provenance and version pinning.
11
+ *
12
+ * SCANNING TARGETS:
13
+ * - agent-manifest.{json,yaml,yml}
14
+ * - agents.{json,yaml,yml}
15
+ * - hermes.config.{js,ts,json,yaml,yml}
16
+ * - openclaw.json
17
+ * - package.json, package-lock.json
18
+ * - .hermes/**
19
+ * - Any file declaring agent versions, integrity hashes, or provenance
20
+ */
21
+
22
+ import fs from 'fs';
23
+ import path from 'path';
24
+ import { createHash } from 'crypto';
25
+ import { BaseAgent, createFinding } from './base-agent.js';
26
+
27
+ // =============================================================================
28
+ // PATTERNS — detected in source files
29
+ // =============================================================================
30
+
31
+ const PATTERNS = [
32
+ // ── Unpinned versions ──────────────────────────────────────────────────────
33
+ {
34
+ rule: 'AGENT_UNPINNED_VERSION_LATEST',
35
+ title: 'Agent: Unpinned version "latest" (ASI-10 Supply Chain)',
36
+ regex: /["'](?:\w*[Vv]ersion|tag|image|ref)["']\s*:\s*["']latest["']/gi,
37
+ severity: 'high',
38
+ cwe: 'CWE-1104',
39
+ owasp: 'ASI-10',
40
+ confidence: 'high',
41
+ description: 'Agent/image version pinned to "latest" — next pull may silently upgrade to a tampered or incompatible version.',
42
+ fix: 'Pin to a specific semantic version (e.g., "1.2.3") or commit SHA.',
43
+ },
44
+ {
45
+ rule: 'AGENT_UNPINNED_VERSION_STAR',
46
+ title: 'Agent: Unpinned version wildcard (* or ^) (ASI-10)',
47
+ regex: /["'](?:\w*[Vv]ersion|tag)["']\s*:\s*["'][\^~*><=][^"']{1,20}["']/gi,
48
+ severity: 'high',
49
+ cwe: 'CWE-1104',
50
+ owasp: 'ASI-10',
51
+ confidence: 'high',
52
+ description: 'Agent version uses a mutable range specifier — version may float to an attacker-controlled release.',
53
+ fix: 'Pin to an exact version string without range operators.',
54
+ },
55
+ {
56
+ rule: 'AGENT_HERMES_UNPINNED',
57
+ title: 'Hermes: @nousresearch/hermes-agent not pinned to exact version',
58
+ regex: /["']@nousresearch\/hermes-agent["']\s*:\s*["'][\^~*><=][^"']{1,20}["']/gi,
59
+ severity: 'high',
60
+ cwe: 'CWE-1104',
61
+ owasp: 'ASI-10',
62
+ confidence: 'high',
63
+ description: 'hermes-agent package version is not pinned — a malicious minor/patch release could modify agent behavior.',
64
+ fix: 'Pin to exact version: "\"@nousresearch/hermes-agent\": \"1.2.3\""',
65
+ },
66
+
67
+ // ── Missing integrity fields ────────────────────────────────────────────────
68
+ {
69
+ rule: 'AGENT_NO_INTEGRITY_HASH',
70
+ title: 'Agent: No integrity hash on remote resource (ASI-10)',
71
+ regex: /["'](?:url|source|registry|endpoint)["']\s*:\s*["']https?:\/\/[^"']{10,}["'](?!\s*,?\s*["']integrity["'])/gi,
72
+ severity: 'high',
73
+ cwe: 'CWE-494',
74
+ owasp: 'ASI-10',
75
+ confidence: 'medium',
76
+ description: 'Remote resource loaded without an integrity hash — no way to detect tampering between publish and load time.',
77
+ fix: 'Add an "integrity": "sha256-..." or "sha512-..." field alongside the URL.',
78
+ },
79
+ {
80
+ rule: 'AGENT_MANIFEST_NO_SIGNATURE',
81
+ title: 'Agent: Manifest loaded without signature verification',
82
+ regex: /(?:loadManifest|readManifest|parseManifest|loadConfig|readConfig|parseConfig)\s*\([^)]{0,80}\)(?!\s*\.(?:verify|checkSignature|assertIntegrity))/gi,
83
+ severity: 'high',
84
+ cwe: 'CWE-345',
85
+ owasp: 'ASI-10',
86
+ confidence: 'medium',
87
+ description: 'Agent manifest is loaded/parsed without a subsequent signature or integrity check — manifest tampering goes undetected.',
88
+ fix: 'Verify manifest signature or compute expected SHA-256 before trusting its contents.',
89
+ },
90
+
91
+ // ── Missing provenance fields ──────────────────────────────────────────────
92
+ {
93
+ rule: 'AGENT_NO_AUTHOR_FIELD',
94
+ title: 'Agent manifest: No author/publisher field',
95
+ regex: /^\s*\{\s*"(?:name|id|version)":/m,
96
+ severity: 'low',
97
+ cwe: 'CWE-1059',
98
+ owasp: 'ASI-10',
99
+ confidence: 'low',
100
+ description: 'Agent manifest has no author or publisher field — provenance cannot be established.',
101
+ fix: 'Add "author", "publisher", or "maintainer" fields with contact information.',
102
+ },
103
+
104
+ // ── Attestation bypass patterns ────────────────────────────────────────────
105
+ {
106
+ rule: 'AGENT_SKIP_INTEGRITY_CHECK',
107
+ title: 'Agent: Integrity check explicitly skipped',
108
+ regex: /(?:skipIntegrityCheck\s*:\s*true|verifyIntegrity\s*:\s*false|integrity\s*:\s*false|bypassAttestation\s*:\s*true|noVerify\s*:\s*true)/gi,
109
+ severity: 'critical',
110
+ cwe: 'CWE-345',
111
+ owasp: 'ASI-10',
112
+ confidence: 'high',
113
+ description: 'Code explicitly disables integrity checking — removes the primary defense against supply-chain attacks.',
114
+ fix: 'Remove the integrity bypass flag and restore verification.',
115
+ },
116
+ {
117
+ rule: 'AGENT_DYNAMIC_REQUIRE_MANIFEST',
118
+ title: 'Agent: Dynamic require/import of manifest path from user input',
119
+ regex: /(?:require|import)\s*\(\s*(?:req\.|request\.|body\.|params\.|process\.env\.[A-Z_]{3,})\s*\)/gi,
120
+ severity: 'critical',
121
+ cwe: 'CWE-706',
122
+ owasp: 'ASI-10',
123
+ confidence: 'medium',
124
+ description: 'Manifest/module path resolved from external input — attacker can redirect load to a malicious file.',
125
+ fix: 'Use a hardcoded manifest path or validate against an allowlist of safe paths.',
126
+ },
127
+
128
+ // ── No changelog / audit trail ────────────────────────────────────────────
129
+ {
130
+ rule: 'AGENT_NO_CHANGELOG_REFERENCE',
131
+ title: 'Agent manifest: No changelog or audit trail reference',
132
+ regex: /^\s*\{\s*(?:(?:"(?:name|id|version|description)":[^}]{0,200})){2,}\}/ms,
133
+ severity: 'low',
134
+ cwe: 'CWE-778',
135
+ owasp: 'ASI-07',
136
+ confidence: 'low',
137
+ description: 'Agent manifest has no changelog, releaseNotes, or auditLog field — version changes cannot be audited.',
138
+ fix: 'Add a "changelog" or "releaseNotes" URL field to the manifest.',
139
+ },
140
+ ];
141
+
142
+ // =============================================================================
143
+ // STRUCTURAL CHECKS
144
+ // =============================================================================
145
+
146
+ const MANIFEST_EXTENSIONS = new Set(['.json', '.yaml', '.yml']);
147
+
148
+ function checkManifestFields(filePath, content) {
149
+ const findings = [];
150
+ let manifest;
151
+
152
+ try {
153
+ // Only handle JSON manifests for deep structural checks
154
+ if (!filePath.endsWith('.json')) return findings;
155
+ manifest = JSON.parse(content);
156
+ } catch {
157
+ return findings;
158
+ }
159
+
160
+ const basename = path.basename(filePath);
161
+ const isAgentManifest = /(?:agent[-_]manifest|agents|hermes\.config|openclaw)/i.test(basename);
162
+ if (!isAgentManifest) return findings;
163
+
164
+ // ── Missing integrity hash on tools array ─────────────────────────────────
165
+ const tools = manifest.tools || manifest.skills || [];
166
+ if (Array.isArray(tools)) {
167
+ for (const tool of tools) {
168
+ const remoteRef = (tool.url || tool.source || '');
169
+ const isRemote = /^https?:\/\//i.test(remoteRef);
170
+ if (isRemote && !tool.integrity && !tool.hash && !tool.checksum) {
171
+ findings.push(createFinding({
172
+ rule: 'AGENT_TOOL_NO_INTEGRITY',
173
+ title: `Tool "${tool.name || tool.id || '?'}" has remote source but no integrity hash`,
174
+ severity: 'high',
175
+ file: filePath,
176
+ line: 0,
177
+ snippet: JSON.stringify(tool).slice(0, 120),
178
+ cwe: 'CWE-494',
179
+ owasp: 'ASI-10',
180
+ confidence: 'high',
181
+ description: `Tool "${tool.name || tool.id}" is loaded from a remote URL without an integrity constraint — can be silently replaced.`,
182
+ fix: 'Add integrity: "sha256-<base64>" to each remotely-sourced tool definition.',
183
+ category: 'supply-chain',
184
+ }));
185
+ }
186
+ }
187
+ }
188
+
189
+ // ── Agent version unpinned (no exact semver) ──────────────────────────────
190
+ const version = manifest.version || manifest.agentVersion;
191
+ if (version && /[\^~*]/.test(String(version))) {
192
+ findings.push(createFinding({
193
+ rule: 'AGENT_MANIFEST_UNPINNED',
194
+ title: 'Agent manifest version uses mutable range',
195
+ severity: 'high',
196
+ file: filePath,
197
+ line: 0,
198
+ snippet: `version: "${version}"`,
199
+ cwe: 'CWE-1104',
200
+ owasp: 'ASI-10',
201
+ confidence: 'high',
202
+ description: 'Manifest version field uses a range specifier — future installs may receive a different agent.',
203
+ fix: 'Use an exact version string without ^ or ~.',
204
+ category: 'supply-chain',
205
+ }));
206
+ }
207
+
208
+ // ── Hermes-specific: missing hermes version pin ───────────────────────────
209
+ const hermesVersion = manifest.hermes?.version || manifest.hermesVersion || manifest.dependencies?.['@nousresearch/hermes-agent'];
210
+ if (hermesVersion && /[\^~*><=]/.test(String(hermesVersion))) {
211
+ findings.push(createFinding({
212
+ rule: 'HERMES_AGENT_UNPINNED',
213
+ title: 'hermes-agent dependency not pinned in manifest',
214
+ severity: 'high',
215
+ file: filePath,
216
+ line: 0,
217
+ snippet: `hermes-agent: "${hermesVersion}"`,
218
+ cwe: 'CWE-1104',
219
+ owasp: 'ASI-10',
220
+ confidence: 'high',
221
+ description: 'The hermes-agent version is not pinned — a compromised minor release would affect all agents using this manifest.',
222
+ fix: 'Pin to exact version: "@nousresearch/hermes-agent": "x.y.z"',
223
+ category: 'supply-chain',
224
+ }));
225
+ }
226
+
227
+ // ── No signature/provenance field at all ─────────────────────────────────
228
+ const hasProvenance = manifest.signature || manifest.provenance || manifest.attestation || manifest.integrity;
229
+ if (!hasProvenance && isAgentManifest) {
230
+ findings.push(createFinding({
231
+ rule: 'AGENT_NO_PROVENANCE',
232
+ title: 'Agent manifest has no signature, provenance, or attestation field',
233
+ severity: 'medium',
234
+ file: filePath,
235
+ line: 0,
236
+ snippet: `(top-level keys: ${Object.keys(manifest).join(', ')})`,
237
+ cwe: 'CWE-345',
238
+ owasp: 'ASI-10',
239
+ confidence: 'high',
240
+ description: 'No attestation metadata found in manifest — cannot verify the manifest was produced by the expected pipeline.',
241
+ fix: 'Add a "provenance" or "signature" field referencing a SLSA attestation or signed hash.',
242
+ category: 'supply-chain',
243
+ }));
244
+ }
245
+
246
+ return findings;
247
+ }
248
+
249
+ // =============================================================================
250
+ // AGENT
251
+ // =============================================================================
252
+
253
+ export class AgentAttestationAgent extends BaseAgent {
254
+ constructor() {
255
+ super('AgentAttestationAgent', 'Agent Attestation & Supply Chain — unsigned manifests, unpinned versions, missing provenance', 'supply-chain');
256
+ }
257
+
258
+ shouldRun() { return true; }
259
+
260
+ async analyze(context) {
261
+ const { files = [], rootPath } = context;
262
+ const findings = [];
263
+
264
+ for (const file of files) {
265
+ const basename = path.basename(file);
266
+ const ext = path.extname(file);
267
+
268
+ // Only scan relevant files
269
+ const isManifest = MANIFEST_EXTENSIONS.has(ext) && /(?:agent|manifest|hermes|openclaw|config)/i.test(basename);
270
+ const isPackageJson = basename === 'package.json';
271
+ const isSourceWithLoad = /\.[jt]s$/.test(ext);
272
+
273
+ if (!isManifest && !isPackageJson && !isSourceWithLoad) continue;
274
+
275
+ let content;
276
+ try {
277
+ content = fs.readFileSync(file, 'utf-8');
278
+ } catch {
279
+ continue;
280
+ }
281
+
282
+ // Skip huge source files that are unlikely to contain manifest loading
283
+ if (isSourceWithLoad && content.length > 200_000) continue;
284
+
285
+ // Pattern-based checks
286
+ const lines = content.split('\n');
287
+ for (let i = 0; i < lines.length; i++) {
288
+ const line = lines[i];
289
+ for (const pattern of PATTERNS) {
290
+ pattern.regex.lastIndex = 0;
291
+ if (pattern.regex.test(line)) {
292
+ findings.push(createFinding({
293
+ rule: pattern.rule,
294
+ title: pattern.title,
295
+ severity: pattern.severity,
296
+ file,
297
+ line: i + 1,
298
+ snippet: line.trim().slice(0, 120),
299
+ cwe: pattern.cwe,
300
+ owasp: pattern.owasp,
301
+ confidence: pattern.confidence || 'medium',
302
+ description: pattern.description,
303
+ fix: pattern.fix,
304
+ category: 'supply-chain',
305
+ }));
306
+ }
307
+ }
308
+ }
309
+
310
+ // Structural checks on manifest files
311
+ if (isManifest || isPackageJson) {
312
+ findings.push(...checkManifestFields(file, content));
313
+ }
314
+ }
315
+
316
+ return findings;
317
+ }
318
+ }
@@ -215,6 +215,41 @@ const PATTERNS = [
215
215
  fix: 'Validate LLM structured output against a schema (Zod, Joi, Pydantic) before processing.',
216
216
  },
217
217
 
218
+ // ── Credential Isolation ─────────────────────────────────────────────────
219
+ {
220
+ rule: 'AGENT_ENV_FILE_ACCESS',
221
+ title: 'Agent: Reads .env Files Without Restriction',
222
+ regex: /(?:readFile|readFileSync|fs\.read|open)\s*\(\s*(?:.*\.env|.*process\.env|.*dotenv)/g,
223
+ severity: 'high',
224
+ cwe: 'CWE-522',
225
+ owasp: 'A02:2021',
226
+ confidence: 'medium',
227
+ description: 'Agent code reads .env files or loads dotenv directly. If the agent is compromised via prompt injection, all credentials in the environment file are exposed.',
228
+ fix: 'Inject only the specific environment variables the agent needs, not the entire .env file. Use scoped credential providers.',
229
+ },
230
+ {
231
+ rule: 'AGENT_NETWORK_AND_FILE_ACCESS',
232
+ title: 'Agent: Both Network and File Access (Exfiltration Risk)',
233
+ regex: /(?:tools|capabilities|functions)[\s\S]{0,800}(?:(?:fetch|http|request|axios|got|curl)[\s\S]{0,400}(?:read|file|fs|disk|path)|(?:read|file|fs|disk|path)[\s\S]{0,400}(?:fetch|http|request|axios|got|curl))/g,
234
+ severity: 'high',
235
+ cwe: 'CWE-200',
236
+ owasp: 'A01:2021',
237
+ confidence: 'medium',
238
+ description: 'Agent has tools for both file access and network requests. This is the exfiltration combination: read credentials from disk, send them over the network.',
239
+ fix: 'Separate file-reading agents from network-capable agents. If both are needed, add human-in-the-loop approval for network requests that follow file reads.',
240
+ },
241
+ {
242
+ rule: 'AGENT_ENV_FORWARDED_TO_TOOL',
243
+ title: 'Agent: Environment Variables Forwarded to Tool',
244
+ regex: /(?:process\.env|os\.environ|ENV)\s*(?:\[|\.)[\s\S]{0,100}(?:tool|function|action|invoke|call|execute)/g,
245
+ severity: 'high',
246
+ cwe: 'CWE-522',
247
+ owasp: 'A02:2021',
248
+ confidence: 'medium',
249
+ description: 'Environment variables (which may contain secrets from Stripe Projects or similar) are forwarded directly to agent tools. A compromised tool receives credentials.',
250
+ fix: 'Pass only the specific variables each tool needs. Never forward the entire process.env to tool invocations.',
251
+ },
252
+
218
253
  // ── Audit & Observability ────────────────────────────────────────────────
219
254
  {
220
255
  rule: 'AGENT_NO_AUDIT_LOG',
@@ -241,6 +241,28 @@ const PATTERNS = [
241
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
242
  fix: 'Remove --dangerously-skip-permissions. Use --permission-mode=workspace-write for CI automation.',
243
243
  },
244
+
245
+ // ── Branch Name Injection (Codex-class attack, CVE pending) ──────────────
246
+ {
247
+ rule: 'CICD_BRANCH_NAME_INJECTION',
248
+ title: 'CI/CD: Unsanitized Branch Name in Shell Command',
249
+ regex: /(?:git\s+(?:checkout|switch|clone\s+--branch|fetch\s+origin))\s+(?:\$\{\{[^}]*(?:head\.ref|branch|ref_name)[^}]*\}\}|\$(?:BRANCH|GITHUB_HEAD_REF|CI_COMMIT_BRANCH|BITBUCKET_BRANCH))/gi,
250
+ severity: 'critical',
251
+ cwe: 'CWE-78',
252
+ owasp: 'CICD-SEC-4',
253
+ description: 'Branch name from an external source (PR head ref, environment variable) is passed directly to a git shell command without sanitization. Attackers can create branches with names containing shell metacharacters to inject arbitrary commands. This is the exact attack vector used in the OpenAI Codex GitHub token theft (BeyondTrust Phantom Labs, Mar 2026).',
254
+ fix: 'Sanitize branch names: strip shell metacharacters, use -- to separate git options from arguments, or use actions/checkout which handles this safely.',
255
+ },
256
+ {
257
+ rule: 'CICD_BRANCH_NAME_IN_RUN',
258
+ title: 'CI/CD: Branch Name Interpolated in run Step',
259
+ regex: /run\s*:\s*[^\n]*\$\{\{\s*(?:github\.head_ref|github\.ref_name)\s*\}\}/g,
260
+ severity: 'high',
261
+ cwe: 'CWE-78',
262
+ owasp: 'CICD-SEC-4',
263
+ description: 'GitHub expression for branch name used directly in a run step. An attacker can craft a branch name with shell injection payloads. This pattern was exploited in the OpenAI Codex vulnerability to steal GitHub OAuth tokens.',
264
+ fix: 'Assign to an environment variable first: env: BRANCH: ${{ github.head_ref }}, then reference as "$BRANCH" (quoted) in the run step.',
265
+ },
244
266
  ];
245
267
 
246
268
  export class CICDScanner extends BaseAgent {