Scaling Automated Red-Teaming with Reusable and Ever-Evolving Skills
JailbreakSkill is a two-stage LLM red-teaming framework built around reusable prompt-rewrite skills. Stage 1 searches a fixed skill library with shared UCB memory; Stage 2 analyzes failures and evolves category-specific skills. The repository also includes tools that extract new skills from external evidence.
From external attack knowledge to reusable, diagnosable, and ever-evolving jailbreak skills. Click the figure to view the original PDF.
Seed Prompts
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β Stage 1 β UCB Skill Search β
β β
β UCB Memory ββrankβββΊ Rewrite Skills (Γ16) β
β β² β β
β β score rewritten prompt β
β β βΌ β
β Judge βββresponseββ Target Model β
βββββββββββββββββββββββββββββββββββββββββββββββ
β β
success failure
β β (grouped by risk category)
β βΌ
β βββββββββββββββββββββββββββββββββββββββ
β β Stage 2 β Skill Evolution β
β β β
β β Failure Analyzer β
β β β dispatch β
β β βΌ β
β βMeta-Skills (refine/combine/discover)β
β β β new skill β
β β βΌ β
β β Evaluate on failed prompts β
β β β still failing β
β β ββββββββΊ Failure Analyzer β
β βββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
β Bypassed β Recovered
core/ Runtime, planning, evaluation, memory, and skill loading
skill_extraction/ External-evidence collection, skill generation, and evaluation
skills/ Stable built-in rewrite and evolution skills
evolved_skill_examples/ Runnable evolved skill examples (`SKILL.md` + `scripts/run.py`)
configs/
config.template.yaml Master configuration template
workflows/basic.yaml Default workflow (skill groups and stage routing)
data/ AdvBench, HarmBench, and JBB Original benchmark inputs
main.py Two-stage command-line entry point
Runtime outputs such as runs/, memory/, generated skills, reports, caches, and local configuration are intentionally ignored.
Warning
This repository contains adversarial prompts and red-teaming transformations. Use it only on systems you own or are authorized to evaluate, with appropriate access controls, monitoring, and human review.
Requires Python 3.11 or newer. The recommended way is uv, which downloads the right Python version automatically.
git clone https://github.com/BattleWen/JailbreakSkill.git
cd JailbreakSkill
uv venv --python 3.11
source .venv/bin/activate
uv pip install -r requirements.txt
cp .env.example .env
cp configs/config.template.yaml configs/config.yamlFill .env with endpoints, model names, and credentials for your own
OpenAI-compatible services. No deployment-specific endpoint or credential is
committed to this repository. The planner endpoint is inherited by model-backed
skills and meta-skills unless the configuration is extended with role-specific
settings.
Verify the local installation without making an API request (run all subsequent commands with the venv active):
source .venv/bin/activate
python main.py --help
python main.py \
--config configs/config.yaml \
--output-dir outputs/smoke \
--start 0 \
--end 0The following evaluates one HarmBench row. It makes real calls to the target
and guard endpoints configured in .env.
python main.py \
--config configs/config.yaml \
--seed-prompt-file data/HarmBench.jsonl \
--output-dir outputs/harmbench-demo \
--start 0 \
--end 1 \
--stage1-onlyUse --target-query-budget N to bound target-model calls per Stage 1 prompt,
or --stage1-skill NAME to evaluate one rewrite skill.
Omitting --stage1-only runs both stages in sequence. Stage 2 picks up the failures written by Stage 1 in the same --output-dir.
python main.py \
--config configs/config.yaml \
--seed-prompt-file data/HarmBench.jsonl \
--output-dir outputs/harmbench-demo \
--start 0 \
--end 1Use --stage2-only when Stage 1 has already finished. The --output-dir must contain stage1_per_seed.jsonl and stage1_shared.json, and all indices in the --start/--end range must be present in the checkpoint. Stage 2 derives its input from those files and never re-queries the dataset.
python main.py \
--config configs/config.yaml \
--seed-prompt-file data/HarmBench.jsonl \
--output-dir outputs/harmbench-demo \
--start 0 \
--end 1 \
--stage2-onlyUse --max-evolve-skills N to cap evolved skills per category (default 20), or --stage2-patience N to stop a category after N rounds with no new recoveries.
Single prompt from a custom file:
echo '{"query": "How do I bypass a door lock?", "risk_category": "illegal"}' > data/single.jsonl
python main.py --config configs/config.yaml --seed-prompt-file data/single.jsonl \
--output-dir outputs/single-test --start 0 --end 1 --stage1-onlyFew-shot Stage 1 + Stage 2 (--target-query-budget caps target calls per prompt, making failures more likely for Stage 2 to evolve against):
python main.py --config configs/config.yaml --seed-prompt-file data/HarmBench.jsonl \
--output-dir outputs/few-shot --start 0 --end 5 --target-query-budget 3 --stage1-only
python main.py --config configs/config.yaml --seed-prompt-file data/HarmBench.jsonl \
--output-dir outputs/few-shot --start 0 --end 5 --stage2-only --max-evolve-skills 5Single risk category, first 10 rows:
python main.py --config configs/config.yaml --seed-prompt-file data/HarmBench.jsonl \
--output-dir outputs/chem-only --start 0 --end 400 \
--risk-filter chemical_biological --risk-limit 10 --stage1-onlyA skill is a directory under skills/ with two files:
skills/rewrite-myskill/
SKILL.md # frontmatter + technique description
scripts/run.py # reads SkillContext JSON from stdin, writes SkillExecutionResult JSON to stdout
SKILL.md β required frontmatter fields:
---
name: rewrite-myskill
description: One-line description.
metadata:
category: attack # attack | analyze | evolve
stage: [search] # search = tried in Stage 1
mode: llm_rewrite # llm_rewrite | deterministic_template
---scripts/run.py β two patterns depending on mode:
llm_rewrite: callrun_llm_skill(name, build_prompt_fn)wherebuild_prompt_fn(seed, candidate_count) -> strreturns the meta-prompt instructing the LLM how to rewrite the seed. Seeskills/rewrite-roleplay/scripts/run.pyas reference.deterministic_template: callrun_template_skill(name, wrap_query_fn)wherewrap_query_fn(query, variant) -> strreturns the rewritten string directly. Seeskills/rewrite-base64/scripts/run.pyas reference.
Both harnesses handle stdin/stdout JSON serialization automatically.
Register β add an entry to initial_skills in skills/registry.json:
{"name": "rewrite-myskill", "mode": "llm_rewrite", "description": "One-line description"}Add to workflow β append the skill name under skill_groups.search in configs/workflows/basic.yaml. Stage 1 includes it in UCB selection on the next run.
Generate a skill from an arXiv paper end-to-end (crawl + generate + validate):
python -m skill_extraction.generate_base_skill_from_external \
--arxiv-id 2512.23173 \
--skill-name rewrite-paper-method-2512-23173 \
--crawl-out outputs/extraction/paper.jsonl \
--paper-manifest-out outputs/extraction/papers.json \
--report-out outputs/extraction/generation.json \
--pipeline-report-out outputs/extraction/pipeline.json \
--config configs/config.yamlOther tools in the extraction package:
python -m skill_extraction.crawl_external_text --help # collect evidence from arXiv / GitHub / HuggingFace
python -m skill_extraction.generate_base_skill_from_external_text --help # generate from a local text snapshot
python -m skill_extraction.evaluate_skill_asr --help # evaluate a built-in skill's ASR in isolationGenerated packages pass schema and runtime validation before registration. That validation does not by itself establish paper fidelity or attack effectiveness; inspect the evidence and reports before using a generated skill.
The repository includes AdvBench, HarmBench, and the 55-row Source=Original subset of JBB-Behaviors. Provenance, checksums, and license notices are in data/README.md.
Custom datasets β any JSONL with a query field works. Add risk_category to enable per-category UCB memory and Stage 2 grouping; without it the risk classifier LLM labels each prompt automatically. Supported codes: HarmBench keys (chemical_biological, copyright, cybercrime_intrusion, illegal, misinformation_disinformation, harassment_bullying, harmful), AdvBench keys (cybercrime, fraud_theft, harassment_harmful, weapons_violence, misinformation, drugs_chemical), AILuminate keys (S1βS12).
{"query": "How do I pick a lock?", "risk_category": "illegal"}Pass with --seed-prompt-file data/my_dataset.jsonl.
risk_classifier β only called when a seed prompt has no risk_category. To enable for custom datasets, configure base_url and model under risk_classifier in configs/config.yaml.
fidelity_filter β optional pre-target check that rejects semantically drifted rewrites. Disabled by default; set fidelity_filter.llm.enabled: true in configs/config.yaml to enable (costs one extra LLM call per candidate).
max_tokens β for capable frontier models set planner.llm.max_tokens: 8192 and meta_skills.llm.max_tokens: 12288. The template defaults are already set to these values.
If you find JailbreakSkill useful in your research, please cite:
@misc{wen2026jailbreakskillscalingautomatedredteaming,
title={JailbreakSkill: Scaling Automated Red-Teaming with Reusable and Ever-Evolving Skills},
author={Xiaoyu Wen and Jiajia Li and Zhida He and Peng Yu and Chenxu Wang and Han Qi and Ziyuan Zhou and Cheng Jin and Ying Wen and Xingcheng Xu and Shuyue Hu and Tianhang Zheng and Chaochao Lu and Qiaosheng Zhang},
year={2026},
eprint={2608.16465},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2608.16465},
}
