DEV Community

Jordan Huang
Jordan Huang

Posted on

Field-Level Golden Tests for Free Model Security Reviews

A pass/fail score hides a lot.

In security triage, I need more than one number.

A model can pass a 30-sample benchmark and still invent a CVE.

So I score each field separately.

That is the core idea.

It sounds simple.

Most builders still stop at one accuracy number.

This post shows a small reproducible harness.

It compares predicted fields against a golden set.

I use MonkeyCode's free model access and free server option as the endpoint under test.

You can swap in any HTTP JSON endpoint.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

Why One Score Breaks

Overall accuracy is an average.

It averages strong fields with weak fields.

A high total can hide one dangerous error.

Take CVE triage as an example.

These fields matter:

  • cve: exact CVE ID from the advisory text.
  • package: affected package or component.
  • severity: ordered level such as low, medium, high, critical.
  • fix_available: true or false based on the advisory.

A wrong CVE is worse than a wrong severity.

But accuracy counts both the same.

That is why I use field-level metrics.

A Small Golden Harness

I keep a golden JSONL file.

Each line has raw advisory text and expected fields.

{"advisory": "CVE-2024-3094 in xz-utils may allow remote code execution via liblzma.", "expected": {"cve": "CVE-2024-3094", "package": "xz-utils", "severity": "critical", "fix_available": true}}
{"advisory": "A medium severity issue in requests may cause header injection.", "expected": {"cve": "CVE-2023-32681", "package": "requests", "severity": "medium", "fix_available": true}}
Enter fullscreen mode Exit fullscreen mode

The scorer compares predicted JSON against expected JSON.

It does not call the model directly.

That keeps the harness testable.

The model output is saved first.

Then the scorer runs.

import json
from pathlib import Path

def exact(expected, predicted):
    return expected == predicted

def token_overlap(expected, predicted):
    a = set(expected.lower().split())
    b = set(predicted.lower().split())
    if not a or not b:
        return 0.0
    return len(a & b) / len(a | b)

def severity_kappa(pairs):
    levels = {"low": 0, "medium": 1, "high": 2, "critical": 3}
    n = len(pairs)
    if n == 0:
        return None
    num = 0.0
    for exp, pred in pairs:
        e = levels.get(exp, 1)
        p = levels.get(pred, 1)
        num += 1.0 - ((e - p) ** 2 / 9.0)
    return num / n

def report(expected_rows, predicted_rows):
    fields = ["cve", "package", "severity", "fix_available"]
    for field in fields:
        exact_hits = 0
        overlap_total = 0.0
        kappa_pairs = []
        for exp, pred in zip(expected_rows, predicted_rows):
            e = exp["expected"].get(field)
            p = pred.get(field)
            if e is None:
                continue
            if exact(e, p):
                exact_hits += 1
            if isinstance(e, str) and isinstance(p, str):
                overlap_total += token_overlap(e, p)
            if field == "severity":
                kappa_pairs.append((e, p))
        kappa = severity_kappa(kappa_pairs) if field == "severity" and kappa_pairs else None
        print(f"{field:12} exact={exact_hits}/{len(expected_rows)} overlap={overlap_total/len(expected_rows):.2f} kappa={kappa}")
Enter fullscreen mode Exit fullscreen mode

This script is deliberately small.

It has no hidden dependencies.

It only reads JSON files.

That makes it easy to rerun.

Why a Dry Run Matters

I test the harness with a stub first.

The stub predicts a wrong CVE on purpose.

It also gives a wrong severity.

The scorer should catch both.

Example run:

python field_diff.py --golden golden.jsonl --predicted stub.jsonl
Enter fullscreen mode Exit fullscreen mode
cve          exact=0/2 overlap=0.00 kappa=None
package      exact=1/2 overlap=0.40 kappa=None
severity     exact=1/2 overlap=0.60 kappa=0.56
fix_available exact=2/2 overlap=0.00 kappa=None
Enter fullscreen mode Exit fullscreen mode

This is not MonkeyCode output.

It is a control run.

The control proves the harness sees field-level failures.

If the dry run shows perfect scores, I check the scorer.

A scoring bug can hide a real model failure.

Running Against a Free Endpoint

I call the endpoint with a small script.

It sends one advisory at a time.

It stores raw JSON responses.

Then I run field_diff.py.

import os, requests, json, time

endpoint = os.environ["MODEL_ENDPOINT"]
with open("golden.jsonl") as fh:
    rows = [json.loads(line) for line in fh if line.strip()]

predictions = []
for row in rows:
    response = requests.post(
        endpoint,
        json={"prompt": row["advisory"], "format": "json"},
        timeout=20,
    )
    predictions.append(response.json())
    time.sleep(1)
json.dump(predictions, open("predictions.json", "w"), indent=2)
Enter fullscreen mode Exit fullscreen mode

This is a generic caller.

It does not assume a specific model name.

It respects conservative pacing.

Free servers often need that.

The free server option helps here.

It gives me a place to run this without a paid key.

But limits exist.

Free servers may rate limit or drop long runs.

I split the golden set into batches.

I save responses immediately.

Then scoring runs offline.

That builds a traceable evaluation trail.

CI Thresholds

A single number is still helpful as a gate.

The trick is to set the threshold per field.

I use --require flags.

field-review:
  image: python:3.12-slim
  script:
    - python field_diff.py --golden golden.jsonl --predicted predictions.jsonl
    - python field_diff.py --require cve:0.95 --require severity:0.75
Enter fullscreen mode Exit fullscreen mode

Why not block on a single number?

Because a bad severity might be acceptable.

A bad CVE is not.

Per-field thresholds make that tradeoff visible.

The CI job fails on the first dangerous field.

You can read the logs without digging.

What I Learned

Field-level scoring changed my checklist.

Overall accuracy is still useful for a quick view.

But it cannot gate security work alone.

I now watch these three failure modes:

  1. CVE hallucination causes wrong remediation links.
  2. Severity drift makes low issues look critical.
  3. Package confusion sends the fix to the wrong component.

The harness catches all three.

It also keeps a JSON trace.

Later, you can compare runs.

That helps detect silent endpoint changes.

Limitations

Do not treat this as a benchmark.

A golden set only tests what you included.

It misses rare inputs.

Free model endpoints can change behavior without notice.

Score them often, but do not trust them blindly.

This harness also does not prove security.

It only checks extraction agreement.

A model can agree with a human and still miss a real risk.

Keep a human in the loop for critical CVEs.

Do not block CI on one free endpoint only.

Add a fallback or a manual review path.

Otherwise a rate limit becomes a release blocker.

Try It

Run the harness against your own endpoint.

Use at least 20 golden samples.

Log the field that fails first.

That field is your real risk.

The dry run above is synthetic.

Your results will differ.

That is the point.

Measure your own failure modes.

Top comments (0)