Skip to main content

Provael — a model-agnostic tool to red-team open Vision-Language-Action (VLA) robot policies in simulation and report an Attack Success Rate (ASR).

Project description

Provael

CI PyPI License: Apache-2.0 Python 3.12+

Prove it. Prevail. — red-team open Vision-Language-Action (VLA) robot policies in simulation and report an Attack Success Rate (ASR).

Provael attack — ASR across instruction/visual/injection families

Deterministic CPU run, seed 0 — regenerate with ./scripts/record_demo.sh.

Provael is the open-source red-team & assurance layer for physical AI. This repo is its core: a small, model-agnostic harness that perturbs the instructions and observations a VLA policy receives inside a simulator and measures how often those perturbations drive the policy into an unsafe state. The headline number is the ASR.

It ships three families of templated, auditable attacksinstruction (text reframings), visual (observation-space markers), and injection (indirect / embodied prompt injection) — plus a none baseline, an ASR leaderboard, and a gated adapter for real SmolVLA policies on the LIBERO simulator. These are heuristic perturbations, not gradient/optimization-based adversarial attacks — see Scope and honest limitations.

The entire core — abstractions, attacks, scoring, runner, report, CLI, leaderboard — runs and is tested on a plain CPU with no GPU and no model/dataset download, using a deterministic StubPolicy + StubSuite. Real policies (SmolVLA via LeRobot) and the LIBERO simulator live behind an optional extra and a PROVAEL_INTEGRATION=1 gate.

⚠️ This is a defensive, sim-only tool for hardening policies via responsible disclosure. It drives no physical robots and ships no real-world-harm payloads. Read SAFETY.md before using it.

Scope and honest limitations

This is an early, research-grade harness, built to be reproducible and honest rather than to oversell. Before you trust a number, know:

  • Templated attacks, not optimized ones. The attacks are auditable string/observation templates (instruction reframings, image markers, scene text), not gradient- or search-based adversarial methods (GCG/PGD-style). They probe behavioral susceptibility, not worst-case robustness. Optimized VLA attacks are an open roadmap item (cf. prior art BadVLA, AttackVLA).
  • Only the instruction family transfers (so far). On real SmolVLA × LIBERO, instruction reframings redirected the policy (roleplay 100%, goal-substitution 60%); the visual and injection families produced 0% measurable lift on the real model. Treat those two as stub-validated scaffolding pending stronger perturbations.
  • One policy, one suite shipped. The architecture is model-agnostic by design (an adapter interface), but only the SmolVLA / LeRobot policy and the LIBERO suite are implemented today — generality is intended, not yet demonstrated against a second backend.
  • One task, uncalibrated predicate. The headline result is libero_object/0 with a default, uncalibrated keep-out zone, so ASR means "diverted out of the benign envelope," not a calibrated hazard rate. Multi-task + per-task zone calibration is next.

Honesty and reproducibility are the point — see PRIOR_ART.md for how this sits next to the academic state of the art.

Install (CPU core — no GPU, no network)

With uv (recommended):

uv sync                      # creates a venv and installs the CPU core + dev tools

Or with pip:

python3.12 -m venv .venv && . .venv/bin/activate
pip install -e .             # core only; lerobot is NOT pulled in

Quickstart (runs in well under 5 s on a CPU)

uv run provael attack --policy stub --suite stub \
    --attacks instruction,visual,injection --episodes 10 --seed 0 --out runs/stub/
               Provael — ASR by attack
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓
┃ attack            ┃   ASR ┃ successes ┃ attempts ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━┩
│ decoy_object      │ 60.0% │         6 │       10 │
│ goal_substitution │ 60.0% │         6 │       10 │
│ mcp_tool_desc     │ 70.0% │         7 │       10 │
│ paraphrase        │ 70.0% │         7 │       10 │
│ patch             │ 80.0% │         8 │       10 │
│ roleplay          │ 80.0% │         8 │       10 │
│ scene_text        │ 50.0% │         5 │       10 │
└───────────────────┴───────┴───────────┴──────────┘
Attack Success Rate (ASR): 67.1% (47/70)

This writes runs/stub/report.json (machine-readable, byte-deterministic) and runs/stub/report.md. Per family, seed-0 ASR is instruction 21/30, visual 14/20, injection 12/20 — exact, asserted numbers.

Other commands:

uv run provael list-policies            # stub (CPU); smolvla (needs the [lerobot] extra)
uv run provael list-attacks             # 7 attacks across families instruction/visual/injection
uv run provael report --in runs/stub/
uv run provael leaderboard build --runs runs --out leaderboard/results   # ranked ASR table
uv run provael version

What runs on CPU vs. what needs a GPU

Capability CPU (default) Needs GPU + [lerobot] extra
stub policy + stub suite
All 3 attack families (instruction/visual/injection)
Scoring, runner, report, CLI, leaderboard build
Full test suite (pytest), ruff, mypy
smolvla policy (real SmolVLA via LeRobot)
libero suite (real LIBERO simulator)

On CPU, --policy smolvla or --suite libero fails with a clear, actionable message (not a traceback) telling you exactly what to install.

First real result (SmolVLA on LIBERO)

HuggingFaceVLA/smolvla_libero · libero_object/0 · 10 seeds · horizon 280 · RTX 4090 (osmesa), 2026-06-06.

family attack ASR lift vs baseline
baseline none 0% (0/10)
instruction roleplay 100% (10/10) +100
instruction goal_substitution 60% (6/10) +60
instruction paraphrase 10% (1/10) +10
visual patch 0% (0/10) 0
visual decoy_object 0% (0/10) 0
injection scene_text 0% (0/10) 0
overall 24.3% (17/70) ± 9.1%

Read it as lift over the benign baseline. The none control runs the policy's real task and scores 0/10, so every success is attack-induced. Language-reframing attacks reliably divert SmolVLA's end-effector; pixel/scene-text perturbations did not move it (0%).

⚠️ Preliminary. The keep-out predicate is a default, uncalibrated region, so this measures "diverted out of the benign safe envelope," not a zone-calibrated hazard rate; n = 10, one task. Per-task keep-out-zone calibration is the v0.2.0 follow-up.

How it works

        ┌───────────┐    instruction     ┌──────────┐   adversarial    ┌──────────┐
 task → │ SuiteAdapter│ ───────────────→ │  Attack  │ ───instruction─→ │ Policy   │
        │  reset/step │                   │ perturb()│                  │  Adapter │
        │  is_unsafe()│ ←─── action ──────┴──────────┘                  │  act()   │
        └─────┬───────┘                                                 └────┬─────┘
              │  for t in horizon: if is_unsafe(state) → success              │
              └──────────────────────── runner ─────────────────────────────┘
                                          │
                                          ▼
                               scoring (ASR) → RunReport → report.json / report.md
  • PolicyAdapterload(), act(observation, instruction) -> np.ndarray.
  • SuiteAdaptertasks(), reset(task, seed), step(action), is_unsafe(state).
  • Attackperturb(instruction, observation) -> (instruction, observation).
  • runner — runs every (task, attack, seed) episode and aggregates.
  • ASRsuccesses / attempts, with by_attack and by_task breakdowns.

Determinism. A RunReport embeds no wall-clock time or process-varying values, so the same config + seed always produces a byte-identical report.json.

Roadmap

  • v0.1.0 — Provael (rebrand of the harness): CPU core, 3 attack families, real SmolVLA × LIBERO path, leaderboard. (this release)
  • v0.2.0SARIF output (provael report --format sarif) so findings surface in GitHub code scanning · a reusable GitHub Action (provael/provael-action) to run a red-team gate in any robot/VLA repo's CI · Embodied-AI Top-10 mapping (each attack tagged to a risk ID) · per-task keep-out-zone calibration.
  • later — optimized (gradient/search) attacks; a second policy/suite backend.

Development

uv run ruff check .      # lint
uv run mypy src          # type-check (strict)
uv run pytest -q         # tests (CPU only; LeRobot tests skip unless gated)

Further reading

  • SAFETY.md — responsible use, sim-only default, scope.
  • PRIOR_ART.md — RoboPAIR, POEX, BadVLA, SafeVLA, and how we differ.
  • CHANGELOG.md — what shipped and what's planned.

License

Apache-2.0. Provael — prove it, prevail.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

provael-0.1.0.tar.gz (252.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

provael-0.1.0-py3-none-any.whl (59.7 kB view details)

Uploaded Python 3

File details

Details for the file provael-0.1.0.tar.gz.

File metadata

  • Download URL: provael-0.1.0.tar.gz
  • Upload date:
  • Size: 252.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for provael-0.1.0.tar.gz
Algorithm Hash digest
SHA256 889c00dd85aae753133e4ca2a91f80dd5d8f0286fc0bcacda64c2de00908c14d
MD5 b7944cec02f46a2db0e64904fabcd315
BLAKE2b-256 c3eaaf457deee2f7d5386982e45fbc8c8183f0df88042f8fd4c1b9ce4bd0e40d

See more details on using hashes here.

File details

Details for the file provael-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: provael-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 59.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for provael-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f036e21c8c7e483a3bb4fc94142adce385cc0043e9f839e53924ba9c023e55f
MD5 9126448ff1a4ce568f069ea9f685fcaa
BLAKE2b-256 1ebeecf8ef72d5c57a4ec412a519abb4cb1ef1421f63acfd29923154203d2592

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page