Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

bezoar

The open-source security scanner for the AI-agent supply chain — skills, MCP servers, plugins, subagents, and CLI add-ons across every major agent platform.

Bezoar: the legendary stone believed to neutralize any poison. This one neutralizes poisoned agent add-ons.

bezoar scan audits an add-on before it enters your agent's context: static detectors, four verdict bands, and a policy layer that turns those bands into decisions. Think npm audit for agent add-ons — offline-first, deterministic, CI-friendly, SARIF/JSON output.

License PyPI SARIF

1.0.0a5 is the deployable product: bezoar serve init, cookie sign-in, multi-arch GHCR images, a live guard, and a five-minute console path. Scanner, inventory, ingest, and policy are unchanged. Install from PyPI; pull images from ghcr.io/ismailkharoub/bezoar-serve.

60-second quickstart

Requires Python ≥ 3.11.

uv tool install 'bezoar==1.0.0a5'
bezoar version
bezoar scan ./skill --fail-on unsafe

Point bezoar scan at any skill directory or repo root. Flags: --format text|json|sarif (reports go to stdout; there is no --output), --fail-on, --config, --changed-since, --baseline. Exit 0 = gate passed, 1 = band ≥ --fail-on, 2 usage, 3 incomplete, 4 internal.

See Getting started for reading findings.

Illustrative text report

The live text reporter prints a band table, then per-component rows. The excerpt below is the finding shape: band is a fact; decision is policy; locations are raw file:line:column; rule ids use <family>/<rule>.

✗  band=malicious  decision=block  components=1  findings=4

generic:skill:pdf-optimizer@<hash12>  malicious → block  (band_default)

  [critical] harness_forgery/control-tag-close      SKILL.md:16:1  [hidden]
             Close of a trusted harness wrapper — the breakout primitive
             evidence: </system-reminder>

  [    high] harness_forgery/control-tag-open       SKILL.md:17:1  [hidden]
             Open of a reminder-role control tag with an imperative body
             evidence: <system-reminder priority="critical">

  [    high] harness_forgery/prose-terminator       SKILL.md:22:1  [hidden]
             Prose-form function-end marker (semantic escape)
             evidence: [Function results halted by user]

  [critical] prompt_injection/instruction-override  SKILL.md:27:1
             Instruction-override language
             evidence: Ignore all previous instructions

--format json and --format sarif are the stable machine interfaces. JSON/SARIF are byte-identical across runs (modulo stats.duration_ms).

Bands and decisions

Band is a fact about the component. Decision is what the org does. No exception, pin, baseline, or vendor trust rewrites a band.

Band (fact) Default decision (policy)
safe allow
potential_risk allow_with_notice
unsafe alert
malicious block

Four bands, four decisions. The three enforcement outcomes people quote (allow / alert / block) are the same table: allow_with_notice is the fourth decision — allow, but surface the risk. Capability-only findings (permissions, unpinned-only supply-chain, metadata) cap the band at potential_risk unless an intent-bearing finding corroborates them. Details: Policy.

Why bezoar

Enterprises deploy coding agents with no seatbelt. Skills and MCPs are executable supply-chain artifacts that load straight into an agent's context. Public scanners catch generic jailbreak phrases and leaked keys; they miss the class that actually steers the model — harness-envelope forgery (content impersonating the host harness's own control syntax). bezoar maps findings to the OWASP Agentic Skills Top 10 and adds that missing family. See Harness-envelope forgery.

A default scan performs no network requests and never executes scanned artifacts. Same inputs → same JSON/SARIF.

Comparison

Public posture as of 2026-09. “Harness-envelope forgery” means a first-class, per-platform vocabulary of harness control syntax plus structural-sequence matchers — not generic “ignore previous instructions” or “system message” regexes.

Offline Deterministic Harness-forgery detection Policy-as-code SARIF Price
bezoar Yes (default) Yes Yes Yes (.bezoar.yml) Yes Apache-2.0
Snyk agent-scan No (SNYK_TOKEN + hosted analysis) No No No (Snyk org / API) No (JSON) Free Snyk account required; commercial platform
Cisco skill-scanner Partial (patterns/YARA offline; LLM optional) Partial (LLM judge optional) No Yes (YAML presets) Yes Apache-2.0
invariantlabs mcp-scan No (Invariant API or OpenAI; connects to MCP servers) No No Partial (proxy guardrails) No Apache-2.0 + cloud / OpenAI
AIR No (inline firewall + cloud) No No Yes (product policy) Not documented Commercial

invariantlabs-ai/mcp-scan now redirects into Snyk agent-scan; the column reflects the historical Invariant CLI that still appears in comparisons. AIR is the commercial category reference — see FAQ.

Docs

Doc What it covers
Five-minute console Init → serve → sign in → ingest → enroll
Getting started Install, first scan, reading findings, exit codes
Policy .bezoar.yml, bands vs decisions, exceptions, vendor trust
Rules authoring Rule-pack schema, severity / disposition / confidence, bezoar rules lint
CI GitHub Action, baselines, SARIF, shipping reports to a console
CI ingest POST /ingest envelope, scoped tokens, HMAC
Web console Static JSON viewer and bezoar serve
Inventory and lifecycle Assets, hosts, finding status / owner / exceptions
Notifications Slack, Teams, email, webhook
Frameworks OWASP / ATLAS / ATT&CK mappings and coverage
Guard Desktop daemon, shims, ceilings, ship-to-serve
MCP gateway stdio wrap + HTTP proxy, tool poisoning
Fetch / trust / quarantine bezoar fetch, promote, trust ledger
Agents llms.txt, well-known, bezoar mcp-server
Self-hosting One-click deploys, compose, /data, upgrade, backup
Serve config bezoar-serve.yml keys, types, env vars
SSO and RBAC token / OIDC / proxy, human and machine roles
Audit and retention Hash-chained JSONL, report pruning
Harness-envelope forgery The differentiator, per-platform vocabularies, tuning
Platforms Discovery matrix and per-platform limits
FAQ Offline, sign-in, token location, ?token=, last_seq, AIR, license

Web console

The console never computes security facts — it renders bezoar.scan/v1 JSON from the CLI.

  • Viewer: open the static export (console/apps/web/out/index.html or bezoar_console.dist_path() after pip install bezoar-console). Drag-drop a JSON report; it stays in IndexedDB. SARIF is rejected — re-scan with --format json.
  • Serve: bezoar serve (loopback + /api/v1). Needs the console extra:
uv tool install 'bezoar[console]==1.0.0a5'
bezoar serve init ./bezoar-data
bezoar serve --data-dir ./bezoar-data

Details: docs/console.md. The five-minute path is docs/quickstart.md.

Try it in five minutes

docs/quickstart.md is the whole path: install → init → sign in → scan → ingest → enroll → first guard event.

Apple Silicon works. ghcr.io/ismailkharoub/bezoar-serve:1.0.0a5 is linux/amd64 + linux/arm64. No --platform.

docker run -d -p 127.0.0.1:8080:8080 -v bezoar:/data \
  ghcr.io/ismailkharoub/bezoar-serve:1.0.0a5

Zero env vars. The entrypoint runs bezoar serve init. Token: docker exec <cid> cat /data/secrets/operator.token. Open /login.

SSO, RBAC, audit, retention stay a YAML file. No SKU.

Then turn on the "enterprise" bits by editing bezoar-serve.yml:

auth:
  mode: oidc
  oidc: { issuer: https://login.example.com, client_id: bezoar, client_secret_file: /run/secrets/oidc }
  roles:
    default: viewer
    groups: { admin: [security-leads], editor: [security-eng] }
audit: { enabled: true }
retention: { reports: { max_age_days: 180 } }
bezoar AIR Alice (Caterpillar)
Self-hosted console Yes — one container No (cloud-only) No
SSO (OIDC) Yes, config Enterprise contract —
RBAC Yes, config (viewer / editor / admin) Enterprise contract —
Audit log Yes — hash-chained JSONL, bezoar audit verify Enterprise contract —
Pricing Apache-2.0 Demo-gated, annual SaaS

Default posture is unchanged: bezoar serve binds loopback, token session, no egress. Every feature above is opt-in. → Self-hosting

GitHub Action

Pin the PyPI package (the Action checkout is private):

# permissions: { contents: read, security-events: write }
- uses: astral-sh/setup-uv@v4
- run: uv tool install 'bezoar==1.0.0a5'
- run: bezoar scan . --format sarif --fail-on malicious > bezoar.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: bezoar.sarif
  if: success() || failure()

bezoar scan --format sarif writes SARIF 2.1.0 on stdout (no --output). Upload that file to Code Scanning after a failed gate too, then re-raise the CLI exit code. Full Action inputs: CI.

License

Apache-2.0. Rule-pack pattern attributions (gitleaks) are in NOTICE and src/bezoar/data/NOTICE.

Metadata

Release files for bezoar 1.0.0a5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bezoar 1.0.0a5
File Size Uploaded Provenance
bezoar-1.0.0a5.tar.gz 726.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for bezoar 1.0.0a5
File Interpreter ABI Platform
bezoar-1.0.0a5-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / bezoar-1.0.0a5.tar.gz

Download URL bezoar-1.0.0a5.tar.gz
Size 726.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5716174002d837afe9b3c6fbdf560bd3eafc35ed878ab4d02ee528ad5807a5d1
BLAKE2b-256 checksum
How to use checksums
08964c52b46cdaca1bda8bb2e47d609008dc625129ef25262c69ba9131f03dd5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / bezoar-1.0.0a5-py3-none-any.whl

Download URL bezoar-1.0.0a5-py3-none-any.whl
Size 533.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0af2cde6ea5438fc11836de626dd855b370c7aae6d2906ac9a8625548a4237b2
BLAKE2b-256 checksum
How to use checksums
e6130290a230ed6e4a1e0ec9c69667f93c70ba7087a1ffeb2ce755521e99219b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Security for bezoar 1.0.0a5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for bezoar-1.0.0a5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page