HarmBench is the most widely cited public corpus for measuring LLM susceptibility to harmful behaviors under attack. Mazeika et al. published it in 2024 with two contributions: a standardized set of 510 behaviors covering categories like cybercrime, chemical and biological weapons, misinformation, and harassment, and an evaluator framework that tests eighteen attack methods against thirty-three target LLMs and defenses 1. The corpus and harness are open source 2.
The argument of this page: HarmBench is the right anchor benchmark for the "can your model be made to do bad things" question, and it is the wrong tool for the "is your product safe" question. Read it as the floor on your model's adversarial robustness, not as a ceiling on your release decision.
What the corpus contains
The 510 behaviors split into four functional categories: 200 standard behaviors (self-contained text prompts), 100 copyright behaviors, 100 contextual behaviors (each comes with a context string), and 110 multimodal behaviors (each comes with an image). Seven semantic categories cut across them: cybercrime and unauthorized intrusion, chemical and biological weapons or drugs, copyright violations, misinformation and disinformation, harassment and bullying, illegal activities, and general harm. The behavior set is intentionally diverse, which is what makes the benchmark useful as a category-level summary but also what makes per-behavior numbers noisy 1. It ships with an official split of 100 validation and 410 test behaviors; tune defenses on the validation set and report on the test set.
The headline number is Attack Success Rate (ASR): the fraction of test cases whose completion the classifier labels as an instance of the target behavior. HarmBench reports ASR. It does not report a refusal rate or a separate gray-middle bucket; a completion either counts as the behavior or it does not, so refusals, deflections, and half-answers all land on the not-counted side. If you want a refusal rate, compute it yourself.
The scoring classifier
HarmBench's evaluator is itself a classifier: a fine-tuned Llama 2 13B chat model for the standard and contextual behaviors, a hashing-based check for copyright behaviors, and a separate validation classifier so attack developers do not tune against the test classifier 1 2. This matters because the classifier is the source of any reproducibility you get out of the benchmark.
Two operational consequences. First, the classifier has its own false-positive and false-negative rates; the paper reports 93.19% average agreement with human labels on its validation set, against 88.37% for a prompted GPT-4 judge 1. Second, when you compare two models on HarmBench, you are comparing them under that classifier's biases. The copyright check is stricter than the others, since the completion has to contain the copyrighted text, which is why copyright ASR runs low; do not average it with the rest without saying so. If you replace the classifier with an LLM-judge of your own, your numbers stop being comparable to the published results. Use the released classifier for any external claim.
Figure: The HarmBench scoring pipeline. Each harmful behavior is paired with one of 18 attack methods, run against a target model (33 in the paper), and the output is graded by the released fine-tuned classifier as an instance of the behavior (attack success, counted in ASR) or not. Refusals are not a separate label.
A minimum-viable run
"""
Minimal HarmBench-style adversarial probe runner.
This is a sketch; the full HarmBench harness handles batching, attack methods,
and standardized prompts. Use the upstream repo for any number you report.
"""
from dataclasses import dataclass
from typing import Callable
@dataclass
class Behavior:
id: str
category: str
behavior: str # natural-language description of the harmful behavior
@dataclass
class AttackResult:
behavior: Behavior
attack_method: str
output: str
asr_label: bool # True if the classifier says success
refusal_label: bool # True if a refusal pattern fired
def run_one(
behavior: Behavior,
attack_prompt: str,
target_model: Callable[[str], str],
classifier: Callable[[str, str], bool],
) -> AttackResult:
"""Single behavior, single attack. The classifier returns True if the
output exhibits the behavior."""
output = target_model(attack_prompt)
asr_label = classifier(behavior.behavior, output)
refusal_label = any(
phrase in output.lower()
for phrase in ("i can't", "i cannot", "i am unable", "i won't")
)
return AttackResult(behavior, "direct", output, asr_label, refusal_label)
def aggregate(results: list[AttackResult]) -> dict:
n = len(results)
asr = sum(r.asr_label for r in results) / n
refusal = sum(r.refusal_label for r in results) / n
return {
"n": n,
"asr": asr,
"refusal": refusal,
"ambiguous": 1.0 - asr - refusal,
}
The toy version above skips three things the real harness handles: standardized attack-prompt construction per attack method (GCG, AutoDAN, PAIR, and more), proper handling of multimodal behaviors, and reproducibility metadata. The refusal flag and the ambiguous bucket in the sketch are its own bookkeeping, not HarmBench outputs; the released classifier returns one label per completion. Use the upstream repo when you want a number that means what the published results mean.
Reading the published numbers honestly
Two failure modes are common when teams read the published HarmBench numbers. HarmBench has no maintained leaderboard: the repo README links none and the project site shows static baseline results, so the figures people quote date from the February 2024 release.
The first is interpreting a single ASR number as a safety score. The number is an average over a category mix that may not match your product. A model with 5% ASR on standard behaviors but 30% on contextual behaviors is differently safe from a model with the opposite profile; the paper itself finds ASR considerably higher on contextual behaviors than on standard ones. Always look at the per-category breakdown the paper publishes alongside the headline.
The second is treating the published numbers as a model-selection input. The 33 targets were the models of early 2024, and the 18 attack methods are frozen with them: the repository's last commit is August 2024 (checked October 2026), after a July 2024 migration of its OpenAI client to the 1.x SDK 2. A 2024 ASR is not directly comparable to a 2026 ASR if the attack methods themselves have improved. Read the numbers as a snapshot, rerun against your current model with a pinned commit of the harness, expect to patch the API clients for current providers, and put the dates of both sides in your release notes.
CAUTION
Public benchmark numbers are an upper bound on capability and a lower bound on overfitting. HarmBench, like any released corpus, will be in some training data by now. The numbers from a fresh private adversarial set you built yourself are usually two to three times higher ASR than the public number on the same model.
Where HarmBench fits in your program
HarmBench earns one row in your standing eval suite, run on every model and prompt change, with the ASR-per-category broken out. Pair it with two other rows: AILuminate (covered in the next chapter) and your own private adversarial corpus. The three together give you a triangulated number that is harder to game than any one of them alone.
The optimization-based attacks in HarmBench (GCG specifically) sit at the edge of practical relevance: they require model-weight access to compute, but produce transferable suffixes 3. If you run HarmBench end-to-end you will produce a small number of transferable adversarial prompts for free; archive them, because they make excellent regression tests once defenses are added.