Skip to content

feat(evals): Add security-review vs wrdn-* coverage matrix - #568

Draft
sentry-junior[bot] wants to merge 11 commits into
mainfrom
feat/security-eval-matrix
Draft

sentry-junior[bot] wants to merge 11 commits into
mainfrom
feat/security-eval-matrix

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Optional security eval suite: does each wrdn-* skill catch bugs builtin security-review misses?

It runs security-review plus wrdn-authz, wrdn-pii, wrdn-data-exfil, wrdn-code-execution and wrdn-dos-review (warden-skills pinned at daf01f9) over the same code. Every lane is scored against the same known bugs, and each wrdn-* lane gets one verdict.

What's in it

The suite is a new package, packages/security-evals. Nothing in packages/evals or .github/workflows/evals.yml changes, so pnpm evals, the run-evals label and the PR Evals workflow never run it.

  • Scenarios: one per entry in sentry-vulnerability-corpus.json (86), plus 47 cases in cases/<skill>/ (25 bugs, 22 clean twins). That makes 133 entries in 53 shards. Cases come from real fix commits in getsentry/sentry, getsentry/sentry-python, getsentry/sentry-wizard and getsentry/dotagents. Every entry pins repo, SHA and targets. A hit on a clean case is a false positive.
  • Repo context: --repo owner/name=<path>, repeatable, with --sentry-repo kept as an alias. Each SHA gets one git worktree add --detach, reused across lanes, entries and repeats. The only network step is a setup-time git fetch for a missing SHA. Without a clone, setup stops with an error.
  • Skills: --skills-repo points at a local warden-skills clone. Setup makes one worktree at the pin and loads each skill once. If that fails, the run stops before any pass.
  • Execution: one Warden pass per shard, with every selected skill on the same file-mode context. The judge applies the corpus rule: same bug, roughly the same location. A failed pass, chunk or judge call counts as an error, never a miss.

Proving a skill

The thresholds are in VERDICT_RULES (src/verdict.ts) and the README:

  • earns-keep: at least one bug the skill caught in 2 of 3 repeats or more, that security-review caught in none, with both lanes at 3+ repeats.
  • no-unique-catches: no such bug, nothing unsettled, and 5+ owned bug cases with 3+ repeats in both lanes.
  • insufficient-evidence: anything else. That covers any errored entry, too few cases, too few repeats, or a catch that security-review gets only some of the time.

The report leads with these verdicts. It never prints a bare "0 caught only by X".

Adding a case

pnpm evals:security:add https://github.com/getsentry/sentry/pull/<n> --skill wrdn-dos-review

The command writes the bug case at the fix's parent and the clean twin at the fix. Targets come from the non-test .py/.ts files the fix modified. Then fill in summary and run the free validator, pnpm -C packages/security-evals test, which is part of regular CI. It checks:

  • the schema and unique ids
  • no overlap with the corpus
  • a known skill directory
  • no TODO summary
  • a clean twin or a noClean reason
  • baseline entries still exist at the same ref

After that, run --entries <ids> --repeats 3 for real.

Baseline

Each lane in baseline/results.json records its runtime, model, effort, aux model, judge, warden version and skill ref. If any of that differs from the current run, the lane is dropped with a warning. The baseline starts empty, because the old imported benchmark lane could never match. baseline:update <results.json> folds in a clean run and refuses results that contain errors.

Running it

git clone --filter=blob:none https://github.com/getsentry/sentry.git ~/src/sentry
git clone https://github.com/getsentry/warden-skills.git ~/src/warden-skills
pnpm evals:security --repo getsentry/sentry=$HOME/src/sentry --skills-repo ~/src/warden-skills \
  --skills security-review,wrdn-dos-review --entries 'wrdn-dos-review/*' --repeats 3

A full pass also needs --repo clones of getsentry/sentry-python, getsentry/sentry-wizard and getsentry/dotagents (see the README). The workflow prepares all four with scripts/prepare-clone.sh <owner/name> <dir>.

Defaults match the production lane: pi, openrouter/x-ai/grok-4.5 at high effort, openrouter/openai/gpt-5.6-luna at high effort for aux, and maxTurns 100. CI runs it through the workflow_dispatch-only Security Evals workflow.

Not done

  • No live run of this package yet. It needs an OpenRouter key and the clones.
  • Owned bug cases: authz 5, dos-review 6, data-exfil 5, code-execution 3, pii 6. Every skill except code-execution can now reach any verdict. Code-execution stays insufficient-evidence until it has 5: fixed, attacker-reachable command, template or deserialization bugs are rare in getsentry history, and most "injection" fixes there are workflow YAML or latent hardening.
  • Next step, not built: harvest candidate cases from production Warden PR comments that led to a fix.
  • Locally, packages/warden's remote.test.ts fails because the sandbox git hook rejects the test's commit author. This PR doesn't touch that code.

via @dcramer.

--

View Session [Sentry]

Run each wrdn-authz scenario under builtin security-review and under
wrdn-authz loaded from a pinned getsentry/warden-skills ref, so the
results show which bugs only the wrdn skill catches.

Seed four scenarios from real getsentry/sentry PR findings that only
wrdn-authz posted, and document how the matrix and the vulnerability
corpus fit together.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
… skills

Add scenario categories for wrdn-code-execution, wrdn-data-exfil, and
wrdn-dos-review, each run under the skill and under security-review.
Bug fixtures come from pre-fix parents of real getsentry/sentry fixes
and corpus entries; clean fixtures use the fixed state of the same file
to count false positives.

Print a per-skill summary after the matrix runs, led by the number of
bugs only the wrdn skill caught.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
@vercel

vercel Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
warden-prod Ready Ready Preview Nov 7, 2026 2:53am UTC

Request Review

@vercel
vercel Bot temporarily deployed to Preview – warden-prod November 7, 2026 01:19 Inactive
@sentry-junior sentry-junior Bot changed the title feat(evals): Add security-review vs wrdn-authz coverage matrix feat(evals): Add security-review vs wrdn-* coverage matrix Nov 7, 2026
Replace the vitest matrix in packages/evals and its vendored sentry
fixtures with packages/security-evals. Skills now scan corpus and case
targets inside a full getsentry/sentry worktree at the pinned SHA, so
they can trace callers and permission code the way they do in prod.

- one scenario per corpus entry plus 15 hand-picked cases (10 bugs,
  5 clean) that record repo, ref, and targets
- one Warden pass per SHA with every selected skill on the same
  context; findings in target files are scored by the corpus rule
- per-lane recall, unique catches, misses by security-review, clean
  flags, cost, and a diffable results JSON
- committed security-review baseline from the two published
  production-config corpus runs
- runs only via pnpm evals:security or the manual Security Evals
  workflow, never from pnpm evals or the PR Evals workflow

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
The first live run lost the whole wrdn-authz lane: every case cloned
getsentry/warden-skills on its own and the clone failed, so the lane
recorded nothing. Resolve the pinned ref once at setup instead.

- --skills-repo (WARDEN_SECURITY_EVALS_SKILLS_REPO) points at a local
  clone; the suite makes one worktree at the pinned SHA and loads
  wrdn-* skills from it by path
- a missing clone or a skill that fails to load stops collection
  once, before any pass, so nothing is scored as a miss
- the Security Evals workflow checks out warden-skills at the pin; a
  unit test keeps the workflow and options.ts pins in sync
- git calls drop Roach's proxy variables, and lazy fetch is only
  disabled for the presence check, so worktrees of blobless clones
  can fetch their blobs
Comment thread packages/security-evals/src/entries.ts Resolved
Comment thread packages/security-evals/src/entries.ts Resolved
Comment thread packages/security-evals/src/baseline.ts Resolved
@semgrep-code-getsentry

Copy link
Copy Markdown

Semgrep found 1 ssc-d25b9656-2752-480c-98ff-eb392322b6e1 finding:

  • packages/security-evals/src/baseline.ts

🟠 High severity issue identified in your code:

Risk: Affected versions of zod are vulnerable to Allocation of Resources Without Limits or Throttling. Zod parses every element of an array, set or map schema and records one validation issue per invalid element, with no cap or early stop. Upper size bounds (.max(), .length(), .size(), or z.maxLength()/z.length()/z.maxSize()/z.size() checks) only ran after all elements had been parsed, so they did not limit the work. An attacker who submits a very large collection (e.g. a million invalid items for z.array(z.string().uuid())) forces the allocation of millions of issue objects, which can exhaust memory and crash the process. Upgrade to zod 4.6.6 or later, which rejects oversized input before parsing its elements when the schema has an upper bound, and add an upper bound (e.g. .max(n)) to every collection schema that parses untrusted input: unbounded schemas stay exposed even after the upgrade.

Fix: Upgrade this library to at least version 4.6.6 at warden/pnpm-lock.yaml:6596.

Reference(s): GHSA-mrhx-c7xc-m3w5, CVE-2023-54404

Add `pnpm evals:security:add <PR or commit URL> --skill <skill>`, which
writes a bug case at the fix's parent and its clean twin at the fix, with
targets inferred from the non-test .py/.ts files the fix modified.

Add a suite validator to the unit tests: schema, unique ids, no corpus
overlap, known skill directory, no TODO summary, a clean twin or noClean
reason, and baseline entries that still exist at the same ref.

Each wrdn-* lane now gets one verdict (earns-keep, no-unique-catches,
insufficient-evidence) from VERDICT_RULES. Failed passes, chunks, and
judge calls count as errors, never misses, and block the verdict.

Baseline lanes record provenance (model, effort, warden version, skill
ref) and are dropped with a warning when it differs from the run. The
old imported benchmark lane could never match, so the baseline starts
empty; baseline:update folds in a clean run.

Replace --sentry-repo with repeatable --repo owner/name=<path>, keeping
the old flag as an alias.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Tilde does not expand after = in a plain argument.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Fix commit getsentry/sentry@d714026543 (contributor could demote an org
admin's inherited team role). Brings wrdn-authz to 5 bug cases.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Fix commits in getsentry/sentry:
- a00270ad6d: unbounded RE2 compile cost for logs regex filters
- b61768dc55: unbounded commits list processed under the release lock
- 1e21009cb0: full=true issue events page serializes 100 full events

Brings wrdn-dos-review to 6 bug cases, each with a clean twin.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Fix commits in getsentry/sentry:
- dd85c7170d: f-string SQL in the missing org members query
- be42554450: caller-chosen ClickHouse function name in fn_span_count
- d84bf17e96: SCIM bearer token rendered in full on the SSO settings page

Brings wrdn-data-exfil to 5 bug cases, each with a clean twin.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Fix commits:
- getsentry/sentry 58b51b430f: UserSerializer returns other users' secondary emails
- getsentry/sentry aedeffac61: activity emails ignore enhanced_privacy
- getsentry/sentry 2204fde687: AI suggested fix ignores the org opt-out
- getsentry/sentry-python f17dad95f3: ASGI query string sent without send_default_pii
- getsentry/sentry-python 5606bb3e58: user attributes on logs and metrics without send_default_pii
- getsentry/sentry-python e52c3b117a: LangChain tool calls recorded without include_prompts

The sentry-python cases need a second clone, so the manual workflow now
prepares both with prepare-clone.sh <owner/name> <dir>.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Fix commits:
- getsentry/sentry-wizard 9a4f3c9282: changed file names interpolated into
  formatter shell commands
- getsentry/dotagents 461da846ce: skill source URL and ref passed to git
  without a -- separator

The manual workflow clones both repositories. wrdn-code-execution has 3 bug
cases; the README lists why it is still short.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>

This branch was successfully deployed

2 active deployments
Preview – warden-prod — 107e13c7 Deployed Nov 7, 2026 by vercel[bot]
Preview – warden — 107e13c7 Deployed Nov 7, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants