Skip to content

Commit 1e2d0e2

Browse files
authored
Merge branch 'main' into fix/remote-dataset-request-timeout
2 parents 4da9c11 + 04e3f84 commit 1e2d0e2

113 files changed

Lines changed: 6151 additions & 302 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎doc/bibliography.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ All academic papers, research blogs, and technical reports referenced throughout
55
:::{dropdown} Citation Keys
66
:class: hidden-citations
77

8-
[@aakanksha2024multilingual; @abughallous2026semguard; @adversaai2023universal; @ahn2025puzzled; @andriushchenko2024tense; @anthropic2024manyshot; @aqrawi2024singleturncrescendo; @atr2026; @banerjee2025safeinfer; @bethany2024mathprompt; @bhardwaj2023harmfulqa; @bhardwaj2024homer; @boucher2023trojan; @brahman2024coconot; @bryan2025agentictaxonomy; @bullwinkel2025airtlessons; @bullwinkel2025repeng; @bullwinkel2026trigger; @chao2023pair; @chao2024jailbreakbench; @choi2026xlsafetybench; @cui2024orbench; @darkbench2025; @derczynski2024garak; @ding2023wolf; @dong2025sata; @embracethered2024unicode; @embracethered2025sneakybits; @evtimov2025wasp; @gehman2020realtoxicityprompts; @ghosh2025aegis; @ghosh2025ailuminate; @gong2025figstep; @gupta2024walledeval; @haider2024phi3safety; @han2024medsafetybench; @han2024wildguard; @hiddenlayer2025policypuppetry; @hines2024spotlighting; @huang2024bijectionlearning; @hughes2024bestofn; @inie2025summon; @ji2023beavertails; @ji2024pkusaferlhf; @jiang2025sosbench; @jones2025computeruse; @kim2023propile; @kingma2014adam; @knight2025fortress; @li2024drattack; @li2024mossbench; @li2024saladbench; @li2024wmdp; @lin2023toxicchat; @liu2024flipattack; @liu2024mmsafetybench; @lopez2024pyrit; @luo2024jailbreakv; @lutz2026pyrit; @lv2024codechameleon; @mazeika2023tdc; @mazeika2024harmbench; @mckee2024transparency; @mehrotra2023tap; @microsoft2024skeletonkey; @odin2024; @palaskar2025vlsu; @pavlova2024goat; @perez2022modelwritten; @pfohl2024equitymedqa; @promptfoo2025ccp; @ren2024codeattack; @robustintelligence2024bypass; @roccia2024promptintel; @rottger2023xstest; @rottger2025msts; @russinovich2024crescendo; @russinovich2025cca; @russinovich2025price; @scheuerman2025transphobia; @shaikh2022second; @shayegani2025computeruse; @shen2023donotanything; @sheshadri2024lat; @souly2024strongreject; @stok2023ansi; @tan2026comicjailbreak; @tang2025multilingual; @tedeschi2024alert; @vantaylor2024socialbias; @vidgen2023simplesafetytests; @wang2023decodingtrust; @wang2023donotanswer; @wang2025siuo; @wang2026visualleakbench; @wei2023jailbroken; @xie2024sorrybench; @yu2023gptfuzzer; @yuan2023cipherchat; @zeng2024persuasion; @zeng2024shieldgemma; @zhang2024cbtbench; @ziems2022mic; @zong2024vlguard; @zou2023gcg]
8+
[@aakanksha2024multilingual; @abughallous2026semguard; @adversaai2023universal; @ahn2025puzzled; @andriushchenko2024tense; @anthropic2024manyshot; @aqrawi2024singleturncrescendo; @atr2026; @banerjee2025safeinfer; @bethany2024mathprompt; @bhardwaj2023harmfulqa; @bhardwaj2024homer; @bhatt2023cyberseceval; @boucher2023trojan; @brahman2024coconot; @bryan2025agentictaxonomy; @bullwinkel2025airtlessons; @bullwinkel2025repeng; @bullwinkel2026trigger; @chao2023pair; @chao2024jailbreakbench; @choi2026xlsafetybench; @cui2024orbench; @darkbench2025; @derczynski2024garak; @ding2023wolf; @dong2025sata; @embracethered2024unicode; @embracethered2025sneakybits; @evtimov2025wasp; @gehman2020realtoxicityprompts; @ghosh2025aegis; @ghosh2025ailuminate; @gong2025figstep; @gupta2024walledeval; @haider2024phi3safety; @han2024medsafetybench; @han2024wildguard; @hiddenlayer2025policypuppetry; @hines2024spotlighting; @huang2024bijectionlearning; @hughes2024bestofn; @inie2025summon; @ji2023beavertails; @ji2024pkusaferlhf; @jiang2025sosbench; @jones2025computeruse; @kim2023propile; @kingma2014adam; @knight2025fortress; @li2024drattack; @li2024mossbench; @li2024saladbench; @li2024wmdp; @lin2023toxicchat; @liu2024flipattack; @liu2024mmsafetybench; @lopez2024pyrit; @luo2024jailbreakv; @lutz2026pyrit; @lv2024codechameleon; @mazeika2023tdc; @mazeika2024harmbench; @mckee2024transparency; @mehrotra2023tap; @microsoft2024skeletonkey; @odin2024; @palaskar2025vlsu; @pavlova2024goat; @perez2022modelwritten; @pfohl2024equitymedqa; @promptfoo2025ccp; @ren2024codeattack; @robustintelligence2024bypass; @roccia2024promptintel; @rottger2023xstest; @rottger2025msts; @russinovich2024crescendo; @russinovich2025cca; @russinovich2025price; @scheuerman2025transphobia; @shaikh2022second; @shayegani2025computeruse; @shen2023donotanything; @sheshadri2024lat; @souly2024strongreject; @stok2023ansi; @tan2026comicjailbreak; @tang2025multilingual; @tedeschi2024alert; @vantaylor2024socialbias; @vidgen2023simplesafetytests; @wang2023decodingtrust; @wang2023donotanswer; @wang2025siuo; @wang2026visualleakbench; @wei2023jailbroken; @xie2024sorrybench; @yu2023gptfuzzer; @yuan2023cipherchat; @zeng2024persuasion; @zeng2024shieldgemma; @zhang2024cbtbench; @ziems2022mic; @zong2024vlguard; @zou2023gcg]
99
:::

‎doc/code/datasets/1_loading_datasets.ipynb‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"CBT-Bench [@zhang2024cbtbench],\n",
2424
"CategoricalHarmfulQA (CatQA) [@bhardwaj2024homer],\n",
2525
"CoCoNot [@brahman2024coconot],\n",
26+
"CyberSecEval [@bhatt2023cyberseceval],\n",
2627
"DarkBench [@darkbench2025],\n",
2728
"DecodingTrust [@wang2023decodingtrust],\n",
2829
"Do Anything Now [@shen2023donotanything],\n",
@@ -122,6 +123,7 @@
122123
" 'coconot_contrast',\n",
123124
" 'coconot_refusal',\n",
124125
" 'comic_jailbreak',\n",
126+
" 'cyberseceval_mitre',\n",
125127
" 'dangerous_qa',\n",
126128
" 'dark_bench',\n",
127129
" 'decoding_trust_toxicity',\n",
@@ -341,9 +343,93 @@
341343
"# Memory has flexible querying capabilities\n",
342344
"(await memory.get_seeds_async(harm_categories=[\"illegal\"], seed_type=\"objective\"))"
343345
]
346+
},
347+
{
348+
"cell_type": "markdown",
349+
"id": "6",
350+
"metadata": {},
351+
"source": [
352+
"## CyberSecEval: Separate Tactics from Harms\n",
353+
"\n",
354+
"CyberSecEval's ten MITRE categories describe cyberattack tactics, not ten distinct harm categories.\n",
355+
"The loader preserves them in `metadata[\"mitre_category\"]` alongside the upstream technique ID/name.\n",
356+
"All prompts receive `COORDINATION_HARM`. C2, Evasion, Execution, Lateral Movement, Persistence and\n",
357+
"Privilege Escalation also receive `MALWARE`; Recon and Discovery are not automatically malware.\n",
358+
"Collection and Exfil receive additional malware/privacy labels only for curated, exact prompt\n",
359+
"matches. The pinned source has 39 `PPI` rows and 13 `PROPRIETARY_INFO` rows, with ten overlapping.\n",
360+
"Generic file transfer or collection does not by itself imply personal or confidential data.\n",
361+
"These are capability labels, not ground-truth judgments that every dual-use response is harmful.\n",
362+
"\n",
363+
"Load the complete dataset into memory first. The following example independently samples three\n",
364+
"prompts from each category, rather than sampling thirty globally and accidentally omitting a\n",
365+
"category. Keep selection in the calling workflow, not in the dataset loader."
366+
]
367+
},
368+
{
369+
"cell_type": "code",
370+
"execution_count": null,
371+
"id": "7",
372+
"metadata": {},
373+
"outputs": [
374+
{
375+
"data": {
376+
"text/plain": [
377+
"{'C2': 3,\n",
378+
" 'Collection': 3,\n",
379+
" 'Discovery': 3,\n",
380+
" 'Evasion': 3,\n",
381+
" 'Execution': 3,\n",
382+
" 'Exfil': 3,\n",
383+
" 'Lateral Movement': 3,\n",
384+
" 'Persistence': 3,\n",
385+
" 'Privilege Escalation': 3,\n",
386+
" 'Recon': 3}"
387+
]
388+
},
389+
"execution_count": null,
390+
"metadata": {},
391+
"output_type": "execute_result"
392+
}
393+
],
394+
"source": [
395+
"import random\n",
396+
"\n",
397+
"from pyrit.datasets.seed_datasets.remote import CyberSecEvalMitreCategory\n",
398+
"\n",
399+
"mitre_datasets = await SeedDatasetProvider.fetch_datasets_async(dataset_names=[\"cyberseceval_mitre\"])\n",
400+
"await memory.add_seed_datasets_to_memory_async(datasets=mitre_datasets, added_by=\"pyrit\")\n",
401+
"\n",
402+
"random_generator = random.Random(0)\n",
403+
"prompts_by_category = {}\n",
404+
"for category in CyberSecEvalMitreCategory:\n",
405+
" population = await memory.get_seeds_async(\n",
406+
" dataset_name=\"cyberseceval_mitre\", metadata={\"mitre_category\": category.value}\n",
407+
" )\n",
408+
" population = sorted(population, key=lambda seed: seed.value_sha256 or seed.value)\n",
409+
" prompts_by_category[category.value] = random_generator.sample(list(population), 3)\n",
410+
"\n",
411+
"{category: len(prompts) for category, prompts in prompts_by_category.items()}"
412+
]
413+
},
414+
{
415+
"cell_type": "markdown",
416+
"id": "8",
417+
"metadata": {},
418+
"source": [
419+
"Keep these category groups when executing and reporting. In a custom scenario, construct one\n",
420+
"`AtomicAttack` per category with `display_group` set to that category; the existing scenario reports\n",
421+
"then show separate results for Recon, Exfil, Persistence, and the other tactics.\n",
422+
"Supply authored `SeedObjective` goals when adapting these literal `SeedPrompt` messages to an\n",
423+
"`AttackSeedGroup`. Do not blindly promote `metadata[\"base_prompt\"]` to an objective: some upstream\n",
424+
"rows contain generation artifacts such as `#ERROR!`. This loader does not reproduce CyberSecEval's\n",
425+
"expansion/judge protocol or decide which responses are harmful."
426+
]
344427
}
345428
],
346429
"metadata": {
430+
"jupytext": {
431+
"main_language": "python"
432+
},
347433
"language_info": {
348434
"codemirror_mode": {
349435
"name": "ipython",

‎doc/code/datasets/1_loading_datasets.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
# CBT-Bench [@zhang2024cbtbench],
2828
# CategoricalHarmfulQA (CatQA) [@bhardwaj2024homer],
2929
# CoCoNot [@brahman2024coconot],
30+
# CyberSecEval [@bhatt2023cyberseceval],
3031
# DarkBench [@darkbench2025],
3132
# DecodingTrust [@wang2023decodingtrust],
3233
# Do Anything Now [@shen2023donotanything],
@@ -121,3 +122,47 @@
121122

122123
# Memory has flexible querying capabilities
123124
(await memory.get_seeds_async(harm_categories=["illegal"], seed_type="objective"))
125+
126+
# %% [markdown]
127+
# ## CyberSecEval: Separate Tactics from Harms
128+
#
129+
# CyberSecEval's ten MITRE categories describe cyberattack tactics, not ten distinct harm categories.
130+
# The loader preserves them in `metadata["mitre_category"]` alongside the upstream technique ID/name.
131+
# All prompts receive `COORDINATION_HARM`. C2, Evasion, Execution, Lateral Movement, Persistence and
132+
# Privilege Escalation also receive `MALWARE`; Recon and Discovery are not automatically malware.
133+
# Collection and Exfil receive additional malware/privacy labels only for curated, exact prompt
134+
# matches. The pinned source has 39 `PPI` rows and 13 `PROPRIETARY_INFO` rows, with ten overlapping.
135+
# Generic file transfer or collection does not by itself imply personal or confidential data.
136+
# These are capability labels, not ground-truth judgments that every dual-use response is harmful.
137+
#
138+
# Load the complete dataset into memory first. The following example independently samples three
139+
# prompts from each category, rather than sampling thirty globally and accidentally omitting a
140+
# category. Keep selection in the calling workflow, not in the dataset loader.
141+
142+
# %%
143+
import random
144+
145+
from pyrit.datasets.seed_datasets.remote import CyberSecEvalMitreCategory
146+
147+
mitre_datasets = await SeedDatasetProvider.fetch_datasets_async(dataset_names=["cyberseceval_mitre"])
148+
await memory.add_seed_datasets_to_memory_async(datasets=mitre_datasets, added_by="pyrit")
149+
150+
random_generator = random.Random(0)
151+
prompts_by_category = {}
152+
for category in CyberSecEvalMitreCategory:
153+
population = await memory.get_seeds_async(
154+
dataset_name="cyberseceval_mitre", metadata={"mitre_category": category.value}
155+
)
156+
population = sorted(population, key=lambda seed: seed.value_sha256 or seed.value)
157+
prompts_by_category[category.value] = random_generator.sample(list(population), 3)
158+
159+
{category: len(prompts) for category, prompts in prompts_by_category.items()}
160+
161+
# %% [markdown]
162+
# Keep these category groups when executing and reporting. In a custom scenario, construct one
163+
# `AtomicAttack` per category with `display_group` set to that category; the existing scenario reports
164+
# then show separate results for Recon, Exfil, Persistence, and the other tactics.
165+
# Supply authored `SeedObjective` goals when adapting these literal `SeedPrompt` messages to an
166+
# `AttackSeedGroup`. Do not blindly promote `metadata["base_prompt"]` to an objective: some upstream
167+
# rows contain generation artifacts such as `#ERROR!`. This loader does not reproduce CyberSecEval's
168+
# expansion/judge protocol or decide which responses are harmful.

‎doc/contributing/4_running_tests.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ The helper's scenarios can also run directly with
7171

7272
For a narrower run, invoke `pytest` directly. You can invoke pytest if it's in your path or via python; either `pytest` or `python -m pytest`. For the following examples, we will use `pytest`.
7373

74+
Analytics correctness tests use a shared, finite 120-second query budget to allow for
75+
SQL compilation and scheduling delays on busy CI workers. Deadline and cancellation
76+
tests use explicit controls and keep their separate timing assertions.
77+
7478
* To run every test under a subdirectory:
7579

7680
```bash

‎doc/gui/0_gui.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,10 @@ API clients can use administrator-only `GET /api/config/runtime`, `POST /api/con
606606
returns HTTP 202 and is tracked in status. Outcomes distinguish busy, unsupported, version-conflict,
607607
invalid-configuration, and restart-required. Authenticated non-admin clients can read readiness and generation only
608608
at `GET /api/runtime`.
609-
`GET /api/health` reports server responsiveness, not runtime readiness.
609+
`GET /api/health` remains HTTP 200 for server responsiveness, even when runtime initialization fails.
610+
It preserves `status`, `timestamp`, and `service`, and includes `ready`, `state`, and the serving ACA
611+
`revision` (or `null` outside ACA) for deployment readiness checks. Responses are uncached and do not
612+
expose configuration or exception details.
610613

611614
---
612615

‎doc/myst.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ project:
9696
- file: scanner/benchmark.ipynb
9797
- file: scanner/foundry.ipynb
9898
- file: scanner/garak.ipynb
99+
- file: scanner/technique.ipynb
99100
- file: code/framework.md
100101
children:
101102
- file: code/datasets/0_dataset.md

‎doc/references.bib‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,14 @@ @misc{banerjee2025safeinfer
890890
note = {AAAI-2025 (AI Alignment track). Introduces the HarmEval benchmark. Dataset: \url{https://huggingface.co/datasets/SoftMINER-Group/HarmEval}},
891891
}
892892

893+
@article{bhatt2023cyberseceval,
894+
title = {Purple Llama {CyberSecEval}: A Secure Coding Benchmark for Language Models},
895+
author = {Manish Bhatt and Sahana Chennabasappa and Cyrus Nikolaidis and Shengye Wan and Ivan Evtimov and Dominik Gabi and Daniel Song and Faizan Ahmad and Cornelius Aschermann and Lorenzo Fontana and Sasha Frolov and Ravi Prakash Giri and Dhaval Kapil and Yiannis Kozyrakis and David LeBlanc and James Milazzo and Aleksandar Straumann and Gabriel Synnaeve and Varun Vontimitta and Spencer Whitman and Joshua Saxe},
896+
journal = {arXiv preprint arXiv:2312.04724},
897+
year = {2023},
898+
url = {https://arxiv.org/abs/2312.04724},
899+
}
900+
893901
@article{kim2023propile,
894902
title = {{ProPILE}: Probing Privacy Leakage in Large Language Models},
895903
author = {Siwon Kim and Sangdoo Yun and Hwaran Lee and Martin Gubri and Sungroh Yoon and Seong Joon Oh},

‎doc/scanner/0_scanner.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ PyRIT ships with scenarios organized into the following families:
6262
| **Benchmark** | AdversarialBenchmark | [Benchmark Scenarios](benchmark.ipynb) |
6363
| **Foundry** | RedTeamAgent | [Foundry Scenarios](foundry.ipynb) |
6464
| **Garak** | Encoding, FigStep, WebInjection, Doctor, SystemPromptExtraction, PackageHallucination, AudioAchillesHeel | [Garak Scenarios](garak.ipynb) |
65+
| **Technique** | Execute | [Execute a Technique](technique.ipynb) |
6566

6667
Each scenario page shows how to run it with minimal configuration.
6768

‎doc/scanner/garak.ipynb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@
620620
"**CLI example:**\n",
621621
"\n",
622622
"```bash\n",
623-
"pyrit_scan run garak.web_injection --target openai_chat --techniques xss --max-dataset-size 1\n",
623+
"pyrit_scan run garak.web_injection --target openai_chat --techniques xss\n",
624624
"```\n",
625625
"\n",
626626
"**Available techniques** (8 probes): MarkdownImageExfil, ColabAIDataLeakage,\n",

‎doc/scanner/garak.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@
221221
# **CLI example:**
222222
#
223223
# ```bash
224-
# pyrit_scan run garak.web_injection --target openai_chat --techniques xss --max-dataset-size 1
224+
# pyrit_scan run garak.web_injection --target openai_chat --techniques xss
225225
# ```
226226
#
227227
# **Available techniques** (8 probes): MarkdownImageExfil, ColabAIDataLeakage,

0 commit comments

Comments
 (0)