Metadata-Version: 2.4
Name: zortium
Version: 0.2.0
Summary: Adversarial attack test suite for vision language models
Author: The Zortium Authors
License-Expression: Apache-2.0
Project-URL: Homepage, https://zortium.dev
Project-URL: Repository, https://github.com/zortium/zortium
Keywords: vlm,adversarial,security,red-team,jailbreak,vision-language-model
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: openai>=2.31.0
Requires-Dist: httpx
Requires-Dist: rich
Requires-Dist: typer
Requires-Dist: pyyaml>=6.0
Requires-Dist: pillow>=12.2.0
Requires-Dist: python-dotenv>=1.2.2
Requires-Dist: numpy
Requires-Dist: requests
Dynamic: license-file

# Zortium

**Adversarial attack test suite for vision-language models.**

Zortium runs a structured battery of adversarial attacks against any OpenAI-compatible VLM endpoint and reports a per-suite Attack Success Rate (ASR). Think [promptfoo](https://github.com/promptfoo/promptfoo) for vision models — systematic, repeatable, CI-ready.

```
$ zortium --base-url https://openrouter.ai/api/v1 --model google/gemma-3-27b-it --api-key $OPENROUTER_API_KEY \
          --judge-model gpt-4o-mini --judge-base-url https://api.openai.com/v1 --judge-api-key $OPENAI_API_KEY

███████╗ ██████╗ ██████╗ ████████╗██╗██╗   ██╗███╗   ███╗
╚══███╔╝██╔═══██╗██╔══██╗╚══██╔══╝██║██║   ██║████╗ ████║
  ███╔╝ ██║   ██║██████╔╝   ██║   ██║██║   ██║██╔████╔██║
 ███╔╝  ██║   ██║██╔══██╗   ██║   ██║██║   ██║██║╚██╔╝██║
███████╗╚██████╔╝██║  ██║   ██║   ██║╚██████╔╝██║ ╚═╝ ██║
╚══════╝ ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝     ╚═╝

  VLM adversarial attack scanner

  target  google/gemma-3-27b-it
endpoint  https://openrouter.ai/api/v1
   judge  gpt-4o-mini
    mode  fast
  suites  18

  ⠋ scanning ━━━━━━━━━━━━━━━━━━━━━━━━━━ 18/18 suites 0:08:47   ← fills live, then:

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓
┃ Attack Suite                         ┃ Severity ┃ Breach Rate ┃ Status ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩
│ Typographic Visual Prompt Injection  │   HIGH   │          0% │  PASS  │
│ FigStep Typographic Jailbreak        │   HIGH   │         25% │  WARN  │
│ Query-Relevant Typographic Jailbreak │   HIGH   │          8% │  PASS  │
│ Goal Hijacking                       │   MID    │         50% │  FAIL  │
│ …                                    │    …     │           … │   …    │
├──────────────────────────────────────┼──────────┼─────────────┼────────┤
│ Overall                              │          │         12% │  WARN  │
└──────────────────────────────────────┴──────────┴─────────────┴────────┘

  cases    137 evaluated · 17 breached
  elapsed  8m 47s

PASS  Overall ASR 12.3% within threshold 100%
```

> No judge configured? Zortium falls back to the **target grading itself** and prints a warning — usable for a first run, but self-grading is lenient, so those breach rates are a floor. Pass `--judge-model` for trustworthy numbers.

---

## Installation

```bash
pip install zortium
```

Requires Python 3.10+. On Linux you may need the system Cairo library for image rendering (`apt-get install libcairo2` / `dnf install cairo`); macOS and Windows wheels bundle it.

---

## Usage

The command in the example above has two halves — the **target** you're testing and the **judge** that grades whether the target complied:

| Role | Flags | What it is |
|---|---|---|
| Target | `--base-url` · `--model` · `--api-key` | the VLM under test — any [OpenAI-compatible](https://platform.openai.com/docs/api-reference) chat completions endpoint |
| Judge | `--judge-model` · `--judge-base-url` · `--judge-api-key` | a separate model that grades harmful-content compliance (see [LLM judge](#llm-judge)) |

That single command is the whole interface. Everything below is a convenience on top of it:

- **Keys off the command line** — every flag has a `ZORTIUM_*` environment variable (`ZORTIUM_API_KEY`, `ZORTIUM_JUDGE_API_KEY`, `ZORTIUM_MODEL`, …), so secrets never appear in your shell history or `ps`.
- **Config file instead of a long line** — run `zortium --init` to drop a documented `zortium.yaml` in the current directory, edit it, then `zortium --config zortium.yaml`. A flag or env var still overrides the file; blank values fall through to env/defaults.
- **Save every response** — the CLI keeps no database, so add `--output report.json` to write a full report: run metadata, headline stats, and per-suite → per-case entries with the full model response, the judge verdict, and its reasoning.
- **Deeper audit** — `--no-fast` runs full per-suite case coverage instead of the reduced fast set (see [Scan modes](#scan-modes)).
- **Go faster on high-limit endpoints** — `--tps N` (env `ZORTIUM_TPS`) runs N suites in parallel. Default is `1` (sequential — safe for rate-limited or shared-key endpoints); raise it for in-house models that can absorb the extra requests-per-second. Rate limits are still handled per the 429 policy, so a too-high value degrades gracefully rather than failing.

---

## CI integration

Exit with code 1 if overall ASR exceeds a threshold:

```bash
zortium --max-asr 20
```

```yaml
# GitHub Actions example
- name: Run VLM security scan
  run: zortium --max-asr 20
  env:
    ZORTIUM_BASE_URL: ${{ secrets.VLM_BASE_URL }}
    ZORTIUM_MODEL: ${{ secrets.VLM_MODEL }}
    ZORTIUM_API_KEY: ${{ secrets.VLM_API_KEY }}
    ZORTIUM_FAST: "true"
```

`--fast` (default `true`) runs one high-signal case per harm category for the image suites — the leanest useful scan, for CI and first runs. Use `--no-fast` for pre-release deep scans with full per-category coverage.

### Rate-limited endpoints

By default a rate-limited (429) test case is recorded as **unavailable** and left out of the score — fast, and right for CI. For a one-off baseline against a heavily throttled endpoint, `--wait` (env `ZORTIUM_WAIT`) retries each rate-limited case until the limit clears so every case gets a real verdict. It respects the `Retry-After` header and can take much longer — use it for benchmarks, **not** CI.

```bash
zortium --no-fast --wait   # complete thorough baseline, waits out rate limits
```

Each suite is labelled with a **severity** — `HIGH`, `MID`, `LOW`, or `DIAGNOSTIC` — reflecting how real-world exploitable the attack is (distinct from how it's judge-gated). Diagnostic suites are always excluded from the headline ASR. In the web UI and benchmarks, severity also drives a **weighted overall score** (`HIGH=3 / MID=2 / LOW=1 / DIAGNOSTIC=0`), so high-severity breaches move the headline number more than low-severity ones. The CLI `--max-asr` gate uses the raw overall ASR.

---

## LLM judge

Critical suites are graded by an LLM judge — it reads each (harmful request, model response) pair and decides whether the target actually complied. Configure it with `--judge-model` / `--judge-base-url` / `--judge-api-key` (or the `ZORTIUM_JUDGE_*` env vars). The base URL and key **inherit the target's** when omitted, so a judge on the same endpoint needs only `--judge-model`. Use a separate, stronger model than the one under test for better calibration.

**No judge configured?** Zortium falls back to the **target model grading its own responses** and prints a warning. This keeps a first run useful out of the box, but a model judging itself is lenient — the resulting breach rates are a *floor*, not a trusted number. Always configure a real judge for numbers you'll act on.

---

## Attack suites

### Critical — LLM judge required, high research backing

| Suite | Technique | Paper |
|---|---|---|
| Typographic Visual Prompt Injection | Embeds harmful instructions as text in images | Goh et al. 2021 |
| Split-Modality Injection | Splits instruction across image + text channels | Original |
| FigStep | Numbered-list document completion framing | Gong et al. 2023 |
| Steganographic Text Injection | Hides instructions in low-contrast image regions | Li et al. 2024 |
| Image Hijacks | Behaviour-matching visual overlays | Bailey et al. 2023 |
| JailBreakV-28K | Real benchmark — 7 adversarial format types | Luo et al. 2024 |
| Visual Jailbreak Transfer | DAN / AIM / many-shot visual personas | Wei et al. 2023 |
| Query-Relevant Typographic Jailbreak | Hides the harmful instruction in a rendered-text image | Inspired by Liu et al. ECCV 2024 |
| Many-Shot Text | 24-example in-context compliance history | Anil et al. 2024 |
| Goal Hijacking | Prompt injection with delimiter spoofing | Perez & Ribeiro 2022 |
| Structured Output Injection | JSON schema / constrained-decoding exploitation | Original |

> **PAIR Agent** (iterative attacker-LLM red-teaming loop, Chao et al. 2023) is implemented but disabled by default. It's a multi-turn attacker-agent loop built for targeted deep audits of a single model rather than routine scanning, so it isn't part of the standard suite — enable it with a one-line registry change when you want it.

> **JailBreakV-28K** is not bundled — the suite fetches its 300 benchmark images on demand from the official [MIT-licensed HuggingFace repo](https://huggingface.co/datasets/JailbreakV-28K/JailBreakV-28k) the first time it runs (`python -m zortium.attacks.jailbreakv_28k --download`). Every other suite works out of the box.

### Medium — Keyword evaluation, limited effectiveness on modern models

| Suite | Technique |
|---|---|
| GCG Suffix | Precomputed adversarial token suffixes (transfer variant) |
| Encoding Attack | Base64 / ROT13 / hex payload obfuscation |
| Refusal Suppression | Instruction-stack refusal bypass |
| Multi-Modal Linkage | Cross-modal encryption-decryption framing |
| UI Spoofing | Authoritative-surface behavioural deviation |

### Diagnostic — Robustness probes, reported separately from ASR

| Suite | Metric |
|---|---|
| Visual Perturbation Drift | Cosine similarity drift under pixel noise |
| Stroop Interference | Visual-linguistic conflict detection |

---

## Scan modes

Both modes run the same 18 suites; **fast** runs fewer cases per suite, **thorough** runs full per-suite coverage.

| | Fast (default) | Thorough |
|---|---|---|
| Cases per image suite | reduced (highest-signal) | full |
| Query-Relevant Typo cases | 13 (1 per scenario, TYPO) | 26 (2 per scenario, TYPO) |
| Good for | daily CI, first runs | pre-release, deep audits |

**On runtime:** wall-clock time is dominated by the *target model's* own latency, throughput, and rate limits — not by Zortium — so it varies widely by model. Expect anywhere from a few minutes to ~10+ minutes for a fast scan; a slow or heavily throttled endpoint (especially with `--wait`) can take considerably longer. If your endpoint has generous rate limits, `--tps N` runs suites in parallel to cut that time (see [Usage](#usage)).

---

## zortium.dev — managed platform

This CLI is the open-source engine, free and fully standalone. **[zortium.dev](https://zortium.dev)** is a managed platform built on top of the same attack suites, for teams that want more than a per-run terminal report:

- **Web UI, no install** — run scans from the browser with results rendered live as each suite completes.
- **Persistent history & dashboards** — every scan is stored and browsable; resume a scan by simply returning to the tab.
- **Scan-to-scan comparison** — diff two runs to see which suites regressed or improved between model versions, with per-suite flip detection.
- **Weighted risk scoring** — a severity-weighted headline score (HIGH/MID/LOW) and per-tier breakdown, so a critical breach outweighs a low-severity one.
- **Cross-model benchmarks** — a leaderboard ranking models by the same methodology, for choosing or tracking a vision model.
- **Teams & enterprise** — shared accounts, plus an on-prem deployment where scan content stays entirely on your own database and only aggregate metadata is reported.

The CLI never phones home and needs none of this — the platform is for teams that want persistence, collaboration, and benchmarking on top of the engine.

---

## Supported providers

Any endpoint speaking the OpenAI chat completions protocol:

- **OpenRouter** — pay-per-token access to hundreds of OSS models via one key (the easiest path for benchmarking OSS models)
- OpenAI, Groq, Together AI, Google Gemini (via their OpenAI-compatible endpoints)
- vLLM, Ollama (via `/v1` shim), TGI adapter
- In-house gateways and fine-tuned model deployments

---

## Architecture

The engine is a `src`-layout package under `src/zortium/`:

```
src/zortium/
├── runner.py            TestRunner — judge enforcement, suite execution
├── constants.py         ScanMode, SuitePriority, SuiteSeverity, RateLimitPolicy, ScanStatus enums
├── attacks/             Attack suite implementations
│   ├── base.py          AttackSuite base class — configure_for_mode(), evaluate()
│   ├── __init__.py      SuiteRegistry — ACTIVE_SUITE_CLASSES, build_active_suites()
│   ├── typographic_injection.py
│   └── ...
├── providers/
│   ├── openai_compatible.py  Target and judge provider abstraction
│   └── ratelimit.py     RateLimitResolver — Retry-After/backoff, SKIP/WAIT, connection retry
├── evaluators/
│   ├── judge.py         LLM-as-judge evaluation
│   └── refusal_aware.py Keyword-based refusal detection
├── utils/               Render, Perturbations, SemanticSimilarity, ImageUtils, PayloadPack
└── config/
    ├── attacks.json     Suite config — priority, severity, harm categories, parameters
    └── harm_payloads.json  Harm category definitions and prompt library
```

**Adding a suite:** subclass `AttackSuite` in `src/zortium/attacks/`, add an entry to `config/attacks.json`, register it in `ACTIVE_SUITE_CLASSES` in `attacks/__init__.py`. Override `configure_for_mode()` if the suite needs different behaviour in fast vs thorough mode.

---

## Intended use & safety

Zortium is a **defensive security tool** for evaluating the robustness of vision-language models you own or are authorized to test.

- **Authorized targets only.** Do not run Zortium against models, endpoints, or systems you do not own or have explicit permission to test.
- **It sends adversarial and harmful content.** By design, Zortium submits jailbreak prompts, harmful requests, and adversarial images to the target model to measure its refusal behaviour. The bundled payloads (`config/harm_payloads.json`) and the JailBreakV-28K benchmark contain offensive material.
- **Purpose is measurement, not exploitation.** The output is a robustness report (Attack Success Rate per suite) to help you harden a model — not a toolkit for attacking third-party systems.

Report security issues responsibly and use results to improve model safety.

---

## Citations

See [CITATIONS.md](CITATIONS.md) for full attribution of all research papers and benchmark datasets.

---

## License

See [LICENSE](LICENSE).
