REQPROOF // FINDINGS LEDGER
TWO ENTRIES · ONE EMBARGOED
NEWEST FIRST · EVERY ENTRY NAMES ITS REVIEWER
reqproof
Public record

Findings we can publish, and the candidates we dropped.

Newest first. Each entry says what review established, which candidates were dismissed and why, and who validated it before it went up. The method and the numbers stay on the record. There's no form on this page.

DATED ENTRIES NAMED VALIDATOR ONE ENTRY EMBARGOED

The ledger · 2 entries

Published

Method, numbers, datelines, and the boundary between what we reported and what we threw away.

Embargoed

One entry sits inside a disclosure window agreed with maintainers. Method and scale only until the release is public.

Validated

A named reviewer signs every entry. The name and the date are on the entry.

§1 The ledger

Two entries. Each names its reviewer.

A finding count is the weakest thing an audit can publish, so this page doesn't open with one. What a stranger can check is whether the work has a shape: a subject, a date, somebody who put their name on it, and an honest account of the candidates that didn't survive review.

Expert-signed, machine-verified. Machine passes raise candidates across the whole declared scope. A named reviewer decides which of them are findings and validates each one before it reaches a client or this page.

Assurance is bounded: within a declared scope, for declared behaviors, with evidence commensurate to the consequence of failure.

The ledger grows one entry at a time, on the cadence the work produces. Entries are appended rather than edited in place.

§2 Entry · July 2026 · public

Hardening a JSON parser that a lot of infrastructure depends on without noticing.

jsonparser is a ten-year-old Go library of ours. Its direct dependents, by the public go.mod record, include Grafana Loki, Keybase, Coroot, the Kubernetes CNI plugins, and the official Sentry and Solana Go SDKs. It's the kind of component nobody writes a risk-register entry for and everybody links against.

We audited it against a formal requirements model rather than against its own tests. The result is 123 formal requirements, traceability across the whole public API, 100% MC/DC, and an audit gate that runs clean. Every artifact lives in the repository, so none of this requires taking our word for it.

Subject

buger/jsonparser, public. Audited by us as the library's maintainer.

Reviewer

Leonid Bugaev. July 2026.

Dependents

The projects named above import the library, as anyone can read off their go.mod files. None of them is a client of ours and we don't present them as one.

Dismissed

Candidates that did not reproduce on a clean tree were dropped rather than reported. A benchmark defect open since 2017 was in scope and is documented separately.

Standing

This is our own library. It demonstrates the method on code you can inspect. It is not a third-party engagement and we do not present it as one.

Eight panic sites, and the eighth in different syntax

The defects mattered more than the score. Passing an empty string as a key-path component could panic across eight separate indexing sites. A sweep for the unsafe pattern found seven. A root-cause review found the eighth, written in a different syntactic shape as keys[depth:][0][0]. A search for one pattern reported all clear while the same assumption survived behind different syntax.

The one that never crashed

Setting an out-of-range index on a scalar array could destroy the existing elements: Set([1,2], "9", "[5]") returned [9] instead of [1,2,9]. No panic, valid JSON, elements gone.

The rest of the set

  • Set and Delete could mutate the caller's input buffer through append on a slice with spare capacity.
  • Delete could emit {"a":1,}.
  • Lone UTF-16 surrogates were synthesized into invalid code points instead of following the standard library.
  • ParseInt("-") returned (0, nil).
  • Get could resolve a path that EachKey failed on.
fig · the sweep resolves, one site out of shape

Where our own method fell short

The scalar-array corruption defect escaped with 100% MC/DC in place. Its branch was covered and both sides were exercised. The wrong input category entered a covered branch, and coverage has nothing to say about which output is semantically correct.

We published that as a blameless proof-gap postmortem instead of hardening the tool without saying so, and turned each escape into a standing obligation: a must-not-mutate-the-input-buffer rule, a cross-API consistency gate, and a benchmark-honesty lint.

Read the postmortem

Why fuzzing had not found it

jsonparser had already been through OSS-Fuzz, which found a real Delete panic and missed these classes. The harness mutated JSON bytes while holding key paths fixed. No byte mutation reaches a panic that requires an empty path component when the path never varies.

That gap produced json-fuzz, and the method later transferred to graphql-fuzz.

§3 Entry · published 29 July 2026 · embargoed

A pre-release audit of a major open-source infrastructure tool, coordinated with its maintainers.

Findings reached the maintainers first. Fixes traceable to the work are landing in the release. Until that release is public we're not naming the tool, its components, the mechanisms, the severities, or how many findings there were.

The entry is here now, dated, and deliberately thin. When the disclosure window closes it gains the tool's name, a link to the release, and the same triage boundary the entry above carries. Nothing else about it changes, which is the point. The credit will confirm a claim that has been sitting on the public record since July rather than announcing a convenient one.

The triage boundary for this entry is embargoed with the findings. Some of the dismissals describe the mechanism of a finding that is still closed, so publishing the boundary now would leak the finding. It ships with the rest of the entry, in the same form as the entry above.

Entry record · embargoed

Dateline

Published here 29 July 2026. The audit window stays undated until the release is public.

Subject

A major open-source infrastructure tool. Not named until the release is public.

Mode

Pre-release audit, coordinated with the maintainers, findings delivered to them first.

Validated by

Leonid Bugaev

Publishable

Method and scale only, until the disclosure window closes.

§4 The finding standard

This is the template. It is not an entry.

TEMPLATE NOT A CORPUS ENTRY EVERY VALUE IS A PLACEHOLDER

Read this as a blank form. Every value below is a placeholder in angle brackets. No commit, no test name, no file path and no finding identifier appears anywhere on this page, because we won't publish an identifier a reader can't resolve. What follows is the shape a client's report takes.

The six sections of a finding

01 Title
Title, status, and affected surface.

Severity, confidence, affected versions, how the behavior was discovered, current status, and the surface it touches.

02 Summary
Summary, and what it changes for you.

The behavior mismatch in plain language, and what it means for the people operating the component. No hypotheticals about worst cases nobody has seen.

03 Expected
Expected against observed.

The behavior the approved requirement declares, quoted, and the behavior the run produced.

04 Reproduction
Minimal reproduction.

The shortest path from a clean tree to the wrong behavior, written so somebody who has never seen the finding can run it.

05 Artifacts
Artifacts and retest.

The reproducer, the assertion it fails, the change that flips it, and the retest result after the client's fix lands.

06 Residual
Residual risk, and what we did not look at.

The adjacent paths, inputs, and behaviors this finding says nothing about. An audit that won't name its own boundary isn't one.

The minimal-reproduction block

# both runs are the reviewer's, before the finding is written

$ <reproducer command>                      # tree as delivered
FAIL  <reproducer name>
      requirement  <the sentence the component is supposed to honor>
      observed     <what the run actually did>

$ <reproducer command>                      # same tree, candidate fix applied
PASS  <reproducer name>

The artifact table

ArtifactWhat it holds
Reproducer<the exact command a reviewer runs, and the tree it runs against>
Failing assertion<the approved requirement the run violates, quoted rather than paraphrased>
Non-vacuity check<the one code change that flips the reproducer from failing to passing, named exactly, so nobody has to take on faith that the test is testing something>
Retest<the result of rerunning the reproducer after the client's fix, with the date it was rerun>
Residual risk<what this finding does not cover: the adjacent paths not reviewed, the inputs not exercised, the behaviors nobody has declared yet>
§5 Severity rationale

Six questions, answered in writing, on every finding.

Severity that arrives as a single word is severity you have to take on faith. These six lines are what a reviewer has to be able to write before a severity is allowed to appear next to a finding. The values below are placeholders, like the rest of the template.

DimensionWhat the finding has to state
Exploitability<who can trigger the behavior, and what access that takes>
Preconditions<the configuration and state the behavior needs before it appears>
Blast radius<what else is affected once it fires, and what is not>
Security boundary<whether a policy, validation, or trust boundary is crossed, and an explicit no when it isn't>
DoS potential<whether the path can be driven to exhaust CPU, memory, or a downstream dependency>
Confidence<how the behavior was established: deterministic reproducer, intermittent reproduction, or reasoned from code and stated as such>

Severity is our own assessment, weighted by reachability and impact, and it is offered as a starting point for your triage. It is not a CVSS score and not a vendor determination.

You own the disposition. Where you disagree with a rating, we record the disagreement next to the finding.

§6 Standing offer

We fund one open-source pre-release audit each quarter.

If you maintain a database, a queue, a runtime, a scheduler, or build tooling that other people run in production, we will audit a release candidate at our own cost. A published entry on this page is worth more to us than the hours it takes, and a maintainer who gets a runnable reproducer out of it is the fair half of that trade.

Write to [email protected] with the component and the release window. If the answer is no, you get a straight one and the reason.

How disclosure works

  • Findings reach the maintainers first, before anyone else sees them.
  • Embargo timing and CVE handling are agreed per finding rather than once per audit.
  • Publication happens after the window closes, and covers only what the maintainers have already seen.
  • Every finding arrives with a runnable reproducer, a named validator, and the list of candidates we dismissed.
  • No invoice, and no commercial follow-up attached to the report. If a maintainer's employer wants to talk about paid work, that's a separate conversation and they start it.
§7 Q.E.D.

That's the whole record.

Two entries is a short ledger and we're not going to dress it up as a long one. It grows one entry at a time, on the cadence the work produces, and every entry that lands here carries a name and a date.

What an audit covers, what it excludes, and how it gets scoped before work starts is on the service page. The method behind the entries, with its stated limits, is on the methodology page.

Validated by Leonid Bugaev, author of GoReplay and jsonparser, who signs both entries above by name. This ledger was published 29 July 2026; when an embargoed entry opens up, the date it first appeared here stays on it.