Evaluate a detector in minutes

Install the SDK, load attack/control pairs in the view your agent sees, and score a detector in Python or from the command line.

GitHub ↗ · Hugging Face ↗

Install

Python 3.10 or later. The SDK is not on PyPI yet; install it from GitHub.

shell
pip install "browsesafe-pp[eval] @ git+https://github.com/perplexityai/browsesafe-plus-plus.git"

Load data

A pair holds two pages: the attacked page and its control. n_pairs=100 loads up to 200 pages; iteration yields the attacked page and then the control of each pair.

python
import browsesafe_pp as bs

bench = bs.load(split="train", n_pairs=100)   # 100 pairs = 200 pages, HTML view
pair = bench.pairs[0]

pair.malicious.content     # attacked page in the selected view
pair.malicious.injected    # True
pair.benign.injected       # False: same page without the injection
pair.metadata              # language, page type, attack type, task, ...

The Hugging Face dataset contains the training split (29,500 pairs). The 9,175-pair test split is reserved for the leaderboard, and a submission endpoint for it is coming soon.

Choose the view with view=, and select by metadata with filters=. Filters match the attacked page and keep its control.

python
md = bs.load(split="train", view="markdown", n_pairs=100)
ax = bs.load(split="train", view="accessibility", n_pairs=100)
spanish = bs.load(filters={"language_payload": ["es"]}, n_pairs=100)

The dataset id can be set with an environment variable:

shell
# Override the SDK's default dataset if needed
export BROWSESAFE_DATASET="perplexity-ai/browsesafe-plus-plus"

Evaluate in Python

A detector is a function that receives one page and returns a prediction. Return bs.Prediction(injected=None) to abstain. The detector input excludes tasks, labels and reference annotations.

python
import browsesafe_pp as bs

def predict(request):
    # request.content: the page in the selected view
    # request.view: "html", "markdown" or "accessibility"
    flagged = "ignore previous instructions" in request.content.lower()
    return bs.Prediction(injected=flagged)

bench = bs.load(split="train", n_pairs=100)
report = bs.evaluate(bench, predict)
report.save("results/my-detector")

Reports include precision, recall, the false-positive rate on control pages, paired correctness, errors and abstentions. Each page gets one attempt; failures are counted, not retried.

Command line

Point --predict at any importable module:function. Run once per view you want to report.

shell
# mymod.py defines predict(request) -> bs.Prediction
browsesafe evaluate --predict mymod:predict --view html \
  --output results/mymod-html
browsesafe evaluate --predict mymod:predict --view markdown \
  --output results/mymod-markdown

Evaluate a hosted model

To score a model behind an OpenAI-compatible chat endpoint, set the endpoint, key and model name. Prompted models on the leaderboard use the published BrowseSafe detection prompt.

shell
export BROWSESAFE_MODEL_ENDPOINT="https://your-endpoint.example/v1"
export BROWSESAFE_API_KEY="..."
export BROWSESAFE_MODEL="your-model-name"

browsesafe evaluate --model "$BROWSESAFE_MODEL" --view html \
  --output results/your-model-html

Adaptive attacks

Static replays understate risk. BrowseSafe-Adapt starts from a benchmark injection, runs a browsing agent on the task, and revises the injection from the agent's behaviour. In the paper, attacks that succeed on a few percent of tasks when replayed succeed on up to 95% after adaptation.

The SDK includes the campaign framework for running adaptive attacks against your own agent; see the adaptive attack guide. The paper's results are on the adaptive leaderboard.