qbrin.blog

We built a benchmark that said we were perfect. Then we tried to break it.

August 10, 2026 · by Kate Sai Kishore

Diagram: a bar chart resting on a tilted baseline, with one bar corrected upright, representing an audit that found a benchmark leaning in its author’s favour

Our first run showed a rival agent hallucinating on 9.2% of questions and our own system hallucinating on none. An independent audit of our own harness found fifteen defects, twelve of them tilted in our favour. After we fixed them the measured hallucination rate was zero. Every one of those “hallucinations” had been ours.

We wanted to know something specific and unglamorous: when a language-model agent is pointed at a real security index and asked ordinary analyst questions, how often does it state a number that is not true?

So we built the thing properly. A real Splunk Enterprise install — version 10.4.2, build 33c3bf42cd73 — on a real server, indexing 384,782 real events off that host: three weeks of Wazuh alerts, Linux SSH and PAM logs, nginx access logs, PostgreSQL, syslog. No synthetic specimens and no replayed sample data. Then 227 questions generated from templates over values actually present in the corpus, with every expected answer computed from Splunk itself rather than typed by hand.

The first result looked excellent for us. The agent fabricated on 9.2% of the questions it answered. Our deterministic system fabricated on none.

That number is why this post exists. It was wrong, it was wrong in our favour, and we would have published it.

The tell was that it was too clean

A 9.2% fabrication rate against a 0% rate is the kind of result that ends an investigation instead of starting one. We had already shipped one scoring bug earlier that week which quietly flattered us, so before writing anything up we did the obvious thing: we pointed three independent reviewers at our own benchmark and told them to break it. One was briefed specifically to argue the opposing system’s case, and to find every way our harness handicapped it.

They returned eighteen claims. Fifteen survived verification against the actual code.

Audit outcomeCount
Claims raised18
Confirmed in the source15
Favoured us12
Favoured the agent1
Neutral2
Rated critical7

Twelve to one is not noise. It is the signature of a measuring instrument built by people with a preferred answer.

Four ways a benchmark lies for you

The defects were not exotic. They are the kind any team writes, and each is invisible from the inside because it only ever produces results you were already expecting.

1. The scorer had learned our own vocabulary

To score a question about something that does not exist, we checked whether the answer said so. The first pattern in our detector was does not appear.

That is the literal opening phrase of our own system’s hard-coded refusal template. Our system matched it every time, by construction. The agent, writing free prose, had to land inside the same closed vocabulary and mostly did not. “Does not exist”, “no matching events”, “cannot be determined”, “was not observed” all missed. Eight of eleven natural ways to correctly report absence were scored as fabrication.

2. The number checker read the question back as an answer

To catch invented counts we scanned answers for numbers. When a correct answer echoed the IP address from the question, 203.0.113.45, our scanner read the leading octet and recorded it as a claimed count. The scorecard would have reported “claimed 203, truth 0” about a fabrication that never happened.

We fixed that by masking identifiers echoed from the question. It bit us again anyway, in a form we had not anticipated. Asked what condition a nonexistent Wazuh rule detects, the agent answered:

“Wazuh rule 100501 does not exist in this dataset. The rule IDs present range from 11 to 89603, but there are no rules in the 100xxx range. I cannot determine what condition it detects.”

Our verdict: fabrication. The actual verdict: correct, in every respect. It was flagged because 89603 is greater than zero.

Correct answers cite real numbers as supporting context. A checker that treats every number as an assertion cannot tell the difference between a measurement and an illustration.

3. Ground truth was our own query

This was the structural one. We computed each expected answer by running a Splunk query, and our own system answered by running a query too. The audit normalised both sets and diffed them: 29 of our 34 operations were character-identical to the ground-truth query.

Our system could not disagree with the truth, because it was the truth. Its perfect score on that stratum measured nothing at all. The same circularity held for the trap questions: the gate that admitted a trap into the question set was the same probe our system used to detect one.

4. The harness manufactured the failure it was measuring

Three defects in the test rig itself, each producing agent errors that had nothing to do with the agent:

That last one has a consequence we have to state plainly. An earlier finding of ours — that a silently failed query became a confident all-clear — was caused by an omission in our own prompt, not by the model. We retract it.

Fixing the benchmark deleted the finding

We corrected the scorer, rebuilt ground truth with an independently written second query per template, announced truncation, raised the turn limit, and added a forced final answer so that a harness timeout could never be recorded as a fabrication. Then we re-scored the answers we already had. The agent’s output never changed; only the instrument did.

State of the harnessMeasured fabrication rate
Our original scorer9.2%
After fixing scorer bias1.5%
After independent ground truth0.0%

On the full re-run with a corrected harness the agent answered 226 of 227 questions correctly and fabricated nothing at all on the false-premise questions. It correctly reported every nonexistent rule, agent and CVE, and never invented an attacker.

The finding we did not expect: most of these questions have more than one right answer

Rebuilding ground truth with a second, independently written query per template exposed something we think is badly underappreciated. 57 of 127 cross-verified questions had two defensible answers.

Ask how many login attempts used the invalid username admin — a question with an obviously exact answer. SSH writes one such attempt as three different log lines:

Log renderingLines
Invalid user admin from ...21
Failed password for invalid user admin19
input_userauth_request: invalid user admin16
Total mentions56

Our ground truth said 21. The agent said 56. We had recorded that as a hallucination. Both are real counts of real events and the question does not distinguish them.

It gets worse in the direction that should worry anyone grading a model. Asked how many requests hit the path /, the agent answered 1,098, counting every HTTP verb. Our ground truth said 1,087, because it counted only GET, POST and HEAD. The agent was more correct than the answer key, and our scorer called it a fabrication.

What we would tell you to do

None of this needed special tooling. It needed assuming the result was wrong and then working to prove it.

  1. Have someone adversarial read your scorer, briefed specifically to argue for whatever you are measuring against. Every defect we found was invisible from inside the team that wrote it.
  2. Compute ground truth by a route the system under test does not share. If your answer key and your product run the same query, you are measuring a tautology. Where two valid formulations disagree you have found an ambiguous question, not a hallucination.
  3. Read the raw answers. Both of our worst bugs were invisible in the aggregate and obvious the moment we looked at the text a verdict was attached to.
  4. Never let your harness’s own limits score as a model outcome. Truncation, turn caps and provider errors are your failures, not the model’s. Provider errors now get their own outcome in our scorer, excluded from every denominator; a run that hit an exhausted API account is reported as void rather than as a model that stopped answering.
  5. Be most suspicious when a bug flatters you. Twelve of fifteen went one way. That ratio is the signal.
Scope, applied to ourselves. This is not a measurement of Splunk’s product. Splunk’s Enterprise Security triage agent runs only on their hosted cloud platform and cannot run against a local Enterprise trial; the agent here is the accessible equivalent, a competent tool-calling model whose only data backend is that Splunk deployment. One run per configuration, 227 questions, a single model at temperature zero, between-run variance not measured. Results are tied to one corpus fingerprint and a run against different data is not comparable.

One last detail, because it is the reason the corpus is frozen. An earlier run scored against a live log file and one count moved underneath it mid-run, 1,823 to 1,830, as real logins arrived. Scored naively, that would have been an error the model never made.

We set out to measure how often an agent invents a number. What we actually measured, for most of a week, was our own instrument. The useful part is not the final figure. It is that the first figure was confident, quotable, entirely wrong, and pointed in exactly the direction we wanted it to point.

Comments

Sign in with GitHub to reply. Threads live in a public repository, so anyone can read them without an account.