muzzle-optimizer
A superred port of MUZZLE (arXiv:2602.09222, "Adaptive Agentic Red-Teaming of Web Agents Against Indirect Prompt Injection Attacks"), an adaptive indirect-prompt-injection (IPI) attacker for tool-using agents.
Given an agentic target and an adversarial goal, MuzzleOptimizer:
- observes one benign run and summarizes the victim's trajectory into a playbook;
- ranks the in-scope content-injection surfaces (vessels) by salience;
- probes a vessel by planting a placeholder and checking it surfaces in the victim's context;
- crafts a context-aware payload with an offline PAIR loop (a simulated victim conditioned on the real system prompt and the localized context);
- attacks with one real run, then refines from feedback: a missed delivery moves to the next vessel, an ineffective payload is re-refined by PAIR.
Success is decided by the SecurityClaim (RunEndEvent.evaluation.success), never by the
optimizer. See ASSUMPTIONS.md for the faithfulness ledger and every
deliberate deviation from the upstream github.com/gsiros/muzzle (SHA ed611c0).
Install
pip install -e ./optimizers/muzzle
Depends only on superred and PyYAML. The Chao et al. PAIR core is vendored under
muzzle_optimizer/pair/ (no cross-module dependency).
Usage
from muzzle_optimizer import MuzzleOptimizer
from superred.core.controller import Controller, TargetFactory
controller = Controller(
optimizer_factory=lambda: MuzzleOptimizer(), # zero-arg; a fresh instance per task
target_factory=TargetFactory(create=make_agent_target, concurrency=1),
security_claim=ipi_claim,
scope=root_scope,
llm_config=attacker_cfg, # the one fixed attacker model MUZZLE's roles share
max_runs_per_task=12, # see "Run budget" below
)
result = await controller.run()
The optimizer adapts entirely from initialize(...); it takes no required constructor
arguments. Useful keyword knobs include max_attempts, the PAIR caps
(pair_n_streams, pair_n_iterations), target_controllable_name (pin a vessel for
ablations), and response_observable_names.
How it maps to the framework
| MUZZLE component | superred |
|---|---|
| Explorer (Docker/Zoo/vLLM-proxy/red-team browser agent) | the controller's run loop + the trajectory + a direct ControllableInjection |
| BENIGN / PROBE / ACTUAL victim runs | successive target.run() calls in the multi-run loop |
| vessel (web UI element) | an in-scope content Controllable (PostCall: tool:<name> / read__* / opi_tool_observation), with PreCall fallback |
| curl assertion oracle | RunEndEvent.evaluation.success (the SecurityClaim) |
| Summarizer / Grafter / Prompter / Judge (gpt-4o agents) | helper classes over the single self.llm, each with its byte-identical prompt |
| PAIR (offline, bare victim LLM) | PairBridge: offline PAIR with self.llm as the surrogate victim |
The optimizer runs a three-phase state machine over the multi-run loop: OBSERVE (passthrough recon -> playbook -> ranked vessels) -> PROBE (placeholder delivery check per vessel; a miss advances the vessel and is not scored) -> ATTACK (inject the PAIR payload; success ends the task, a UI-attributed failure tries the next vessel, an instruction-attributed failure re-refines).
Scope behavior
- Content vessels in scope: the intended IPI setting; rank, probe, attack.
- PreCall-only: degrade to a
user_prompt(preferred) orsystem_promptfallback vessel (less indirect, deprioritized). - No injectable surface: one OBSERVE passthrough, then
done(the passthrough baseline). Never crashes. include_feedback=False: steers by the trajectory presence/PROBE checks only and never self-certifies success.
Run budget
OBSERVE is a pure recon run, so a single phase cannot attack. Allow at least ~4-5 runs per
goal (max_runs_per_task) so OBSERVE + PROBE + ACTUAL can complete; the offline PAIR loop
consumes only the optimizer's LLM cost budget, not target runs. BudgetExhaustedError stops
the task cleanly.
Tests
pip install -e "./optimizers/muzzle[test]"
pytest optimizers/muzzle/tests -q
mypy --strict optimizers/muzzle/src
ruff check optimizers/muzzle
smoke/ holds env-gated live end-to-end checks against real agentic targets (agentdojo,
inspect_agent); they need an LLM proxy (LITELLM_API_KEY / LITELLM_API_BASE).
Credits / upstream
This module ports the MUZZLE red-teaming method to superred and vendors the
PAIR attacker core. Our integration code is MIT (see LICENSE); upstream
components keep their original licenses (see NOTICE and LICENSES/).
- MUZZLE — Syros et al., "MUZZLE: Adaptive Agentic Red-Teaming of Web Agents
Against Indirect Prompt Injection Attacks", arXiv:2602.09222 (2026).
Source: https://github.com/gsiros/muzzle (Apache-2.0). The five agent prompt
YAMLs, the four injection templates, the judge payload-presence heuristic, and
the OBSERVE/PROBE/ATTACK control logic derive from this repo. Deviations from
upstream are logged in
ASSUMPTIONS.md. - PAIR — Chao et al., "Jailbreaking Black Box Large Language Models in Twenty
Queries" (2023). Source: https://github.com/patrickrchao/JailbreakingLLMs
(MIT, Copyright (c) 2023 PAIR Team). Vendored under
muzzle_optimizer/pair/.
Please cite both papers when reporting results produced with this module.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file superred_optimizer_muzzle-0.1.0.tar.gz.
File metadata
- Download URL: superred_optimizer_muzzle-0.1.0.tar.gz
- Upload date:
- Size: 82.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2452ddfd97d9a82c0db8198e9c715daaca9b1e7a7af375edb3da61acf881b904
|
|
| MD5 |
f3d3d08ff0e6d9c67edbde692758a70a
|
|
| BLAKE2b-256 |
525aa3a49e60bc620b5b4902fee8821e239c03c2aed1cf13c4c5c382c689a177
|
Provenance
The following attestation bundles were made for superred_optimizer_muzzle-0.1.0.tar.gz:
Publisher:
release.yml on RoldSI/superred-modules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
superred_optimizer_muzzle-0.1.0.tar.gz -
Subject digest:
2452ddfd97d9a82c0db8198e9c715daaca9b1e7a7af375edb3da61acf881b904 - Sigstore transparency entry: 2219230342
- Sigstore integration time:
-
Permalink:
RoldSI/superred-modules@44b3a2514b4d75fe7ebc3f015aa13ff3b6e8380c -
Branch / Tag:
refs/tags/superred-optimizer-muzzle-v0.1.0 - Owner: https://github.com/RoldSI
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@44b3a2514b4d75fe7ebc3f015aa13ff3b6e8380c -
Trigger Event:
push
-
Statement type:
File details
Details for the file superred_optimizer_muzzle-0.1.0-py3-none-any.whl.
File metadata
- Download URL: superred_optimizer_muzzle-0.1.0-py3-none-any.whl
- Upload date:
- Size: 67.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75c3e411449bb31f20ef5e77117cd6932f61bcc12aec0c931313654faf6b052c
|
|
| MD5 |
eab55bad513fad8c657a4be6ccc2b23d
|
|
| BLAKE2b-256 |
f23b1963f179081d6e49d7027c3db1b65aded93d586a74d8346faba2429b3e0e
|
Provenance
The following attestation bundles were made for superred_optimizer_muzzle-0.1.0-py3-none-any.whl:
Publisher:
release.yml on RoldSI/superred-modules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
superred_optimizer_muzzle-0.1.0-py3-none-any.whl -
Subject digest:
75c3e411449bb31f20ef5e77117cd6932f61bcc12aec0c931313654faf6b052c - Sigstore transparency entry: 2219230391
- Sigstore integration time:
-
Permalink:
RoldSI/superred-modules@44b3a2514b4d75fe7ebc3f015aa13ff3b6e8380c -
Branch / Tag:
refs/tags/superred-optimizer-muzzle-v0.1.0 - Owner: https://github.com/RoldSI
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@44b3a2514b4d75fe7ebc3f015aa13ff3b6e8380c -
Trigger Event:
push
-
Statement type: