Start here

Bawbel Scanner

Open-source CLI scanner for agentic AI components — SKILL.md files, MCP servers, system prompts, plugins. Detects AVE vulnerabilities before they reach production.

$ pip install bawbel-scanner

Run your first scan

# Scan a file
bawbel scan ./my-skill.md

# Full remediation report
bawbel report ./my-skill.md

# Recursive scan, fail on HIGH+
bawbel scan ./skills/ --recursive --fail-on-severity high

# Watch mode
bawbel scan ./skills/ --watch

What is covered

40+ detection rules

Pattern rules mapped 1:1 to AVE records. Plus 3 new rules in v1.2.0: hook hijacking, credentials, delegation chains.

6 detection engines

Pattern, YARA, Semgrep, LLM semantic analysis, Magika file-type verification, Docker behavioral sandbox.

3 output formats

Text for humans, JSON for tooling, SARIF for GitHub Security tab and any SIEM.

Justified suppression

New in v1.2.0. Every suppression requires a reason and reviewer. Accepted risks resurface on expiry.

Installation

Installation

Requires Python 3.10+. The base install uses no optional dependencies.

pip install bawbel-scanner            # core - pattern engine only
pip install "bawbel-scanner[yara]"    # + YARA rules
pip install "bawbel-scanner[semgrep]" # + Semgrep rules
pip install "bawbel-scanner[llm]"     # + LLM semantic engine
pip install "bawbel-scanner[all]"     # everything

Verify

bawbel version
Bawbel Scanner v1.2.0

Detection Engines:
  ✓  Pattern     40 rules  ·  always active
  ✓  YARA        v4.5.x   ·  active
  ✓  Semgrep     v1.159.0 ·  active
  ✗  LLM         not installed
  ✗  Sandbox     disabled
CLI Reference

bawbel scan

Scan a component or directory for AVE vulnerabilities.

bawbel scan PATH [OPTIONS]

Options

OptionDefaultDescription
--formattexttext · json · sarif
--fail-on-severityExit 2 if findings at or above: critical high medium low
--recursive, -rfalseScan all matching files in a directory tree
--no-ignorefalseDisable all suppressions — audit mode
--watch, -wfalseWatch for file changes and re-scan

Exit codes

CodeMeaning
0Clean, or findings below threshold
2Findings at or above --fail-on-severity threshold
CLI Reference — New v1.2.0

bawbel creds & bawbel chain

Focused scans that filter to a specific threat category. Both use the same output format as bawbel scan.

For a full security scan use bawbel scan. bawbel creds and bawbel chain are for targeted triage sessions or specialized CI gates.

bawbel creds

Filters to bawbel-hardcoded-credential (AVE-2026-00047) only. Detects API keys, tokens, passwords, private key blocks, and URL-embedded credentials.

bawbel creds ./skills/ --recursive
bawbel creds ./skills/ --fail-on-any
bawbel creds ./skill.md --format json

bawbel chain

Filters to bawbel-unsafe-delegation (AVE-2026-00048) only. Flags sub-agent spawning with inherited permissions and no trust boundary.

bawbel chain ./skills/ --recursive
bawbel chain ./skills/ --fail-on-any
bawbel chain ./skill.md --format json

Shared options

OptionDescription
--recursive, -rScan directory recursively
--no-ignoreDisable all suppressions
--fail-on-anyExit 2 if any finding is found
--formattext (default) or json
CLI Reference — New v1.2.0

bawbel accept

Mark a finding as a false positive or accepted risk. Inserts a justified suppression comment directly into the source file. The comment is the canonical record — no external database.

# Mark as false positive (permanent suppression)
bawbel accept AVE-2026-00001 ./skill.md --line 7 \
  --reason "Internal registry endpoint, not attacker-controlled" \
  --type false-positive

# Mark as accepted risk with 90-day expiry
bawbel accept AVE-2026-00047 ./skill.md --line 3 \
  --reason "Placeholder value, replaced at deploy time" \
  --type accepted-risk \
  --expires 90d

# List all accepted findings
bawbel accept --list

# Show findings expiring within 30 days (exits 1 in CI when within 14 days)
bawbel accept --expiring-soon --within 30

# Send anonymous FP signal to PiranhaDB
bawbel accept AVE-2026-00001 ./skill.md --line 7 \
  --reason "Internal endpoint" \
  --type false-positive \
  --report

Expiry formats

FormatExample
Relative days90d
Relative months3m
Relative years1y
ISO date2026-08-16
v1.2.0 — New

Justified suppression

The existing bawbel-ignore silently removes findings. Justified suppression requires a human-readable reason, records a reviewer, and supports expiry dates for accepted risks.

False positive

The finding matched the pattern but the content is not dangerous. Suppressed permanently.

<!-- bawbel-ignore: AVE-2026-00001
     reason: Internal registry endpoint, not attacker-controlled
     reviewer: chaksaray
     reviewed: 2026-05-16
-->

Accepted risk

The finding is real but the behavior is intentional and reviewed. When the expiry passes, the finding resurfaces as active on the next scan.

<!-- bawbel-accept: AVE-2026-00047
     reason: Placeholder value, replaced at deploy time by CI pipeline
     reviewer: chaksaray
     reviewed: 2026-05-16
     expires: 2026-08-16
-->

Expired accepted risks resurface automatically as active findings. The finding's suppression_reason will say accepted_risk_expired with the original reviewer and date.

JSON audit trail

Justified suppressions appear in accepted_findings in JSON output — separate from suppressed_findings.

{
  "accepted_findings": [{
    "ave_id":           "AVE-2026-00047",
    "suppression_type": "accepted_risk",
    "reason":           "Placeholder replaced at deploy time",
    "reviewer":         "chaksaray",
    "expires_at":       "2026-08-16",
    "days_until_expiry": 92,
    "is_expired":       false
  }]
}
Detection

Suppression

Four mechanisms for suppressing false positives, plus the automatic FP pipeline.

Inline comment

content  <!-- bawbel-ignore -->
content  <!-- bawbel-ignore: bawbel-external-fetch -->
content  <!-- bawbel-ignore: AVE-2026-00001 -->
content  # bawbel-ignore
content  // bawbel-ignore

Block suppression

<!-- bawbel-ignore-start -->
... all findings in this section suppressed ...
<!-- bawbel-ignore-end -->

.bawbelignore

docs/**
tests/fixtures/**
examples/**

Audit mode

bawbel scan ./skills/ --no-ignore
bawbel report ./skill.md --no-ignore

Automatic FP pipeline

LayerMechanism
FP-1Code fence stripping — content inside ``` blocks blanked before analysis
FP-2Negation context — lines preceded by "Never do this:" or "Bad example:"
FP-3Confidence scoring — docs/ and examples/ paths reduce confidence
FP-4LLM meta-analyzer — medium-confidence findings reviewed by LLM (optional)
v1.2.0 — New

New AVE records in v1.2.0

Rule IDAVE IDSevAIVSSDescription
bawbel-hook-hijack AVE-2026-00046 CRITICAL 9.1 MCP tool hook hijacking — registers hooks to intercept all tool calls
bawbel-hardcoded-credential AVE-2026-00047 HIGH 7.8 Hardcoded API keys, tokens, passwords, and URL-embedded credentials
bawbel-unsafe-delegation AVE-2026-00048 HIGH 8.2 Sub-agent spawning with inherited permissions and no trust boundary
Detection

Detection engines

Six independent engines. Each returns list[Finding]. Results merge and deduplicate before toxic flow analysis.

1a

Pattern — always active

40 regex rules mapped to AVE records. Stdlib only, completes in under 5ms. No install needed.

1b

YARA — pip install "bawbel-scanner[yara]"

39 YARA rules. Multi-condition matching, string combinations, case variations. Catches things regex misses.

1c

Semgrep — pip install "bawbel-scanner[semgrep]"

41 structural rules. Spans multiple lines, context-aware. Runs as external subprocess.

2

LLM — pip install "bawbel-scanner[llm]" + API key

Semantic analysis via LiteLLM. Catches synonym attacks, multi-paragraph injections, novel patterns. Auto-detects provider from API keys.

3

Sandbox — Docker + BAWBEL_SANDBOX_ENABLED=true

Dynamic behavioral analysis. Executes the component in a locked-down container and monitors actual runtime behavior.

Every engine skips silently when its dependency is not installed. scan() always completes and always returns a result — it never raises.

Integration

CI/CD

# .github/workflows/bawbel.yml
- name: Bawbel scan
  uses: bawbel/scanner@v1
  with:
    path: ./skills/
    fail-on-severity: high
    format: sarif
    output: bawbel.sarif

- name: Upload to GitHub Security
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: bawbel.sarif

Check expiring accepted risks in CI

# Warn when accepted risks expire within 14 days (exits 1)
bawbel accept --expiring-soon --within 14
Integration

Pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/bawbel/scanner
    rev: v1.2.0
    hooks:
      - id: bawbel-scan
        args: [--fail-on-severity, high]
API

Output formats

bawbel scan ./skills/ --format text    # human-readable (default)
bawbel scan ./skills/ --format json    # machine-readable, includes accepted_findings
bawbel scan ./skills/ --format sarif   # SARIF 2.1.0 for GitHub Security / GHAS

JSON output includes accepted_findings (new in v1.2.0) alongside the existing findings and suppressed_findings arrays.