Security scanner orchestrator for AI agent skills. This package coordinates multiple scanning tools in parallel, scores severity, and produces structured reports.
npm install @yourclaw/clawguard-scannerFor local development as part of the ClawGuard project:
cd ../clawguard && make setupimport { scanSkill } from "@yourclaw/clawguard-scanner";
const report = await scanSkill("/path/to/skill", {
builtinOnly: false, // set true to skip external tools
skipAi: true, // skip AI review
format: "json", // json | markdown | sarif
});
console.log(report.status); // "passed" | "warning" | "blocked"
console.log(report.severityScore); // 0-100
console.log(report.findings); // Finding[]npx @yourclaw/clawguard-cli scan /path/to/skill
npx @yourclaw/clawguard-cli scan /path/to/skill --builtin-only --skip-ai
npx @yourclaw/clawguard-cli scan /path/to/skill --format sarifThe scanner runs multiple tools in parallel using Promise.allSettled for
graceful degradation. If an external tool is not installed, that scanner is
skipped without failing the overall scan.
| Adapter | Tool | What it scans | Required? |
|---|---|---|---|
| Builtin Pattern Matcher | @yourclaw/clawguard-rules |
Prompt injection, secrets, malware, permissions | Built-in |
| Gitleaks | gitleaks | Hardcoded secrets & credentials | Optional |
| Semgrep | semgrep | Custom code patterns (eval, shell injection) | Optional |
| MCP-Scan | mcp-scan | MCP server configuration issues | Optional |
| npm audit | npm | Known CVEs in dependencies | Optional |
| AI Review | Claude API | Ambiguous cases needing judgement | Optional |
npx @yourclaw/clawguard-cli doctorFindings are scored on a 0–100 scale with category-based multipliers:
| Category | Multiplier |
|---|---|
| Prompt injection | 2.0x |
| Malware | 1.5x |
| Secrets | 1.2x |
| Permissions | 1.0x |
Individual severity weights:
| Severity | Points |
|---|---|
| critical | 25 |
| high | 15 |
| medium | 8 |
| low | 3 |
The final score is capped at 100.
| Score | Status | Recommendation |
|---|---|---|
| 0 | passed |
install |
| 1–30 | warning |
install_with_warning |
| 31–70 | warning |
prompt_user |
| 71+ | blocked |
block |
Full machine-readable report with all findings, metadata, and scores.
Human-readable report suitable for GitHub issues or PR comments.
SARIF 2.1.0 format for integration with GitHub Code Scanning, VS Code, and other SARIF-compatible tools.
The scanner supports a .clawguard-ignore JSON file for suppressing known
false positives. Place it in your skill directory (or any parent directory) and
the scanner will automatically discover it by walking up the directory tree.
This feature was introduced to support the YourClaw OpenClaw fork upstream sync pipeline, where automated scans of upstream releases can surface false positives that need to be documented and suppressed transparently. See PR #4 for the initial set of suppressions and the analysis behind each one.
You can also pass an explicit path via the ignoreFile option:
const report = await scanSkill("/path/to/skill", {
ignoreFile: "/path/to/.clawguard-ignore",
});
// Suppressed findings are still available for auditing
console.log(report.suppressed); // Finding[] (what was filtered out)
console.log(report.suppressionCount); // number{
"suppressions": [
{
"id": "unique-id-for-this-suppression",
"rule": "the-rule-name-or-finding-id",
"file": "path/fragment/to/match",
"scanner": "semgrep",
"justification": "Why this is a false positive",
"addedBy": "your-name",
"addedAt": "2026-03-02",
"reference": "https://github.com/your-org/your-repo/pull/123"
}
]
}| Field | Required | Description |
|---|---|---|
id |
Yes | Unique identifier for this suppression entry |
rule |
Yes | Must match the finding's name or id field |
file |
Yes | Substring match against the finding's file path |
scanner |
Yes | Which scanner produced the finding (semgrep, clawguard-rules, gitleaks, etc.) |
justification |
Yes | Explanation of why this finding is a false positive |
addedBy |
Yes | Person or bot that added the suppression |
addedAt |
Yes | Date the suppression was added (ISO 8601 date) |
reference |
No | URL to the PR, issue, or discussion that discovered and analyzed the finding |
A finding is suppressed when both conditions are true:
suppression.ruleequals the finding'snameorid- The finding's file path contains
suppression.fileas a substring
Every suppression should include a reference URL pointing to the PR or issue
where the finding was discovered, analyzed, and confirmed as a false positive.
This creates a transparent audit trail so that anyone reviewing suppressions
can understand the full context behind each decision.
For automated pipelines (e.g. upstream sync workflows), the reference should
link to the sync PR that first flagged the finding — giving future reviewers a
direct path to the scan results, code analysis, and team discussion.
Use suppressions only for confirmed false positives — cases where the scanner flags code that is actually safe. If a finding points to a real issue, fix the code instead of suppressing it.
Good reasons to suppress:
- A
shell: trueflag is used safely with hardcoded arguments (no user input) - A unicode escape sequence is used for data formatting, not obfuscation
- A regex pattern triggers a secrets scanner but is not an actual secret
Bad reasons to suppress:
- The finding is inconvenient to fix right now
- You disagree with the rule's severity (file an issue on the rule instead)
interface Finding {
id: string; // e.g. "PI-001"
severity: "critical" | "high" | "medium" | "low";
category: string; // e.g. "prompt-injection"
message: string;
file?: string;
line?: number;
scanner: string; // which adapter found it
}
interface ScanReport {
status: "passed" | "warning" | "blocked";
severityScore: number;
recommendation: string;
findings: Finding[];
metadata: SkillMetadata;
scannedAt: string;
}# Install dependencies
npm install
# Run tests
npm run test:run # single run
npm test # watch mode
# Build
npm run build
# Lint
npm run lint- Create
src/scanners/my-adapter.ts. - Implement the adapter function returning
Finding[]. - Use
isCommandAvailable()fromutils.tsfor graceful skip. - Register in
src/orchestrator.tsinsidescannerTasks. - Add tests in
test/.
make install # npm install
make build # tsup build
make test # vitest run
make lint # biome check
make clean # remove dist/ and node_modules/See the main CONTRIBUTING.md
for guidelines. The scanner is a great place to contribute new integrations —
each adapter is a self-contained file in src/scanners/.