Skip to main content

ExhibitA

An AI security reviewer that proves the fix — not just the finding.

Exploit it. Patch it. Verify it. On an open model, offline.

License: MIT Gemma 4 Runs offline Agent Skill


Scanners produce long lists of warnings, most of which developers learn to ignore. ExhibitA does something different: it asks the open Gemma 4 model to explain each finding and filter the noise, and for the serious ones it proves the bug is real — it runs the app in an isolated sandbox, confirms the vulnerability with a black-box exploit, applies the AI's fix, and checks the exploit no longer works while the app still behaves.

Every finding comes with evidence.

It runs three ways from one core — a CLI, a GitHub Action, and an Agent Skill — against either the cloud Gemini API or a fully offline local model.

How it works

 your code / pull request
        │
 1. SCAN     Semgrep · Gitleaks · Hadolint · Checkov   (Docker, no network)
        │
 2. TRIAGE   Gemma 4 explains each finding, filters false positives, suggests a fix
        │
 3. PROVE    for critical bugs: run the app in a sandbox and confirm the exploit,
        │    apply the fix, confirm it's blocked, confirm the app still works
        │
 4. REPORT   terminal · SARIF (Security tab) · PR comments with one-click fixes
        │
 5. GATE     fail the build only on a *proven* critical — no proof, no block

The proof uses the same black-box techniques a DAST scanner uses — a boolean true/false difference, a /etc/passwd read, a timing delay, an evaluated expression, an unescaped reflection — so it confirms the bug on real apps, not just a crafted demo. The target runs through its own Dockerfile when it has one, so the language and framework don't matter.

What it finds

Proven exploitable in the sandbox (6 classes): SQL injection · command injection · path traversal · server-side template injection · reflected XSS · XXE.

Detected, explained, and fixed: Flask debug mode, eval/exec, unsafe yaml.load, SSRF, weak hashing; hardcoded secrets (Gitleaks); Dockerfile issues (Hadolint); Kubernetes / Terraform / GitHub Actions misconfig (Checkov).

Why it's different

Scanners (Semgrep, Snyk…) AI pentesters (Strix, Shannon…) ExhibitA
Finds issues ✅ ✅ ✅
Proves the bug is real ❌ ✅ ✅
Proves the fix works & nothing breaks ❌ — ✅
One-click fix in the PR — ❌ ✅
Blocks a merge only with proof ❌ ❌ ✅
Runs offline on an open model ❌ partial ✅

Quickstart

pip install -e .
docker build -t exhibita-sandbox:latest sandbox/     # for self-contained apps

# offline: install Ollama, then
ollama pull gemma4:e4b

exhibita scan demo/vulnerable_app                     # scan + AI triage
exhibita verify demo/vulnerable_app                   # scan + triage + sandbox proof

Pick a backend with MODEL_BACKEND=ollama (offline) or MODEL_BACKEND=gemini (set GEMINI_API_KEY). Switch explanation language with --lang te.

Offline isn't the fallback — it's the fast path. With gemma4:e4b on a laptop GPU the whole review runs with the Wi-Fi off; nothing leaves the machine.

The interfaces

  • CLI — exhibita scan / exhibita verify (above).
  • GitHub Action — action.yml + .github/workflows/review.yml: on every PR it posts inline review comments with one-click fixes, uploads SARIF to the Security tab, and fails the check only on a proven critical. Open the PR from a branch (not a fork) and set GEMINI_API_KEY as a repo secret.
  • Agent Skill — skills/exhibita/SKILL.md, compliant with the Agent Skill open standard, so a coding agent can check its own changes before opening a PR.
  • MCP server — python -m exhibita.mcp_server exposes scan, verify, and threat_model over the Model Context Protocol, so any MCP-aware agent can call ExhibitA as a tool.

Configuration

An optional .exhibita.yml selects scanners, ignore paths, the gate threshold, the language, and — for frameworks beyond Flask — declares the HTTP routes to prove against.

Benchmark

On OWASP Juice Shop (a real, intentionally-vulnerable app), Semgrep's registry rules raise a wall of alerts; ExhibitA explains each, and 11 of 26 server-side alerts fall into classes it can prove exploitable when the app is run. See BENCHMARK.md (reproduce with python scripts/benchmark.py).

Honest scope

ExhibitA genuinely proves bugs on self-contained web apps it can run (its own Dockerfile, or a Python app in the sandbox image). What it does not yet do: run multi-service apps that need a live database, locate routes automatically outside Flask (declare them in .exhibita.yml), or write custom code rules for languages other than Python (the secret and infrastructure scanners are language-agnostic). Those are the roadmap, not claims.

Development

pip install -e ".[dev]"
pytest                      # 56 unit tests; 3 Docker integration tests when Docker is up
python scripts/capture_fixtures.py   # refresh scanner fixtures from the demo app

Built with AI

Per MLH rules, AI tools used: Claude Code (pair-programming the implementation) and Gemma 4 (the review engine itself, via Ollama and the Gemini API).

License

MIT. Built on open tools — Semgrep, Gitleaks, Hadolint, Checkov — and Google's open Gemma 4 model.

Metadata

Release files for exhibita 0.1.0

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

Source distribution (sdist)

Source distribution for exhibita 0.1.0
File Size Uploaded
exhibita-0.1.0.tar.gz 62.5 kB Details

Built distribution (wheel)

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

Total release size: 110.7 kB

Release files / exhibita-0.1.0.tar.gz

Download URL exhibita-0.1.0.tar.gz
Size 62.5 kB
Tags Source
SHA-256 checksum
How to use checksums
d666672001034ab21a6242f821e3b4fbf5ae3c0e77666f46f26e077fda0e0730
BLAKE2b-256 checksum
How to use checksums
f6c367e0633c53a70b95a3de395b00eec5b6891ae33a34eba9b0af00d56d4274
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / exhibita-0.1.0-py3-none-any.whl

Download URL exhibita-0.1.0-py3-none-any.whl
Size 48.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
efa29744df25bcbe99abfe2d2a1e3e6be695d1cbc2d131cdbf1c29f41c60851b
BLAKE2b-256 checksum
How to use checksums
25590fe335e96d41070bce0d80d00927abad5769041222bbcb197d74efbcb2d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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