Ground-Truth Corpus Specification

Implementation status (verified 2026-07-19): design target, partially implemented. The supported subset is the manifest model and deterministic metrics/classification library under src/Scanner/__Libraries/StellaOps.Scanner.Benchmark/. The separate StellaOps.Scanner.Benchmarks assembly exposes ICorpusRunner and result-writing models, but has no concrete runner or production registration. Its CLI builder is not attached to the current command tree. The checked-in vulnerability corpus at src/__Tests/__Benchmarks/competitors/corpus/corpus-manifest.json contains placeholder image digests and no labelled findings, while the reachability corpus index under src/__Tests/__Datasets/reachability/ references sample paths that are not all present. Therefore the benchmark and CI commands below describe the recovery contract; they are not currently runnable acceptance instructions. Verify current composition in src/ before using them.

Version: 1.0.0
Last Updated: 2025-12-17
Source Advisory: 16-Dec-2025 - Building a Deeper Moat Beyond Reachability

This document specifies the ground-truth corpus for benchmarking StellaOps’ binary-only reachability analysis and deterministic scoring.


Overview

A ground-truth corpus is a curated set of binaries with known reachable and unreachable vulnerable sinks. It enables:


Corpus Structure

Sample Requirements

Each sample binary must include:

Manifest Schema

{
  "$schema": "https://stellaops.io/schemas/corpus-sample.v1.json",
  "sampleId": "gt-0001",
  "name": "vulnerable-sink-reachable-from-main",
  "format": "elf64",
  "arch": "x86_64",
  "compiler": "gcc-13.2",
  "compilerFlags": ["-O2", "-fPIE"],
  "stripped": false,
  "obfuscation": "none",
  "pie": true,
  "cfi": false,
  "sinks": [
    {
      "sinkId": "sink-001",
      "signature": "vulnerable_function(char*)",
      "address": "0x401234",
      "cveId": "CVE-2024-XXXXX",
      "expected": "reachable",
      "expectedPaths": [
        ["main", "process_input", "parse_data", "vulnerable_function"]
      ],
      "expectedUnreachableReasons": null
    },
    {
      "sinkId": "sink-002", 
      "signature": "dead_code_vulnerable()",
      "address": "0x402000",
      "cveId": "CVE-2024-YYYYY",
      "expected": "unreachable",
      "expectedPaths": null,
      "expectedUnreachableReasons": ["no-caller", "dead-code-elimination"]
    }
  ],
  "entrypoints": [
    {"name": "main", "address": "0x401000"},
    {"name": "_start", "address": "0x400ff0"}
  ],
  "metadata": {
    "createdAt": "2025-12-17T00:00:00Z",
    "author": "StellaOps QA Guild",
    "notes": "Basic reachability test with one true positive and one true negative"
  }
}

Starter Corpus (20 Samples)

Category A: Reachable Sinks (10 samples)

IDDescriptionFormatStrippedObfuscationExpected
gt-0001Direct call from mainELF64NoNoneReachable
gt-0002Indirect call via function pointerELF64NoNoneReachable
gt-0003Reachable through PLT/GOTELF64NoNoneReachable
gt-0004Reachable via vtable dispatchELF64NoNoneReachable
gt-0005Reachable with stripped symbolsELF64YesNoneReachable
gt-0006Reachable with partial obfuscationELF64NoControl-flowReachable
gt-0007Reachable in PIE binaryELF64NoNoneReachable
gt-0008Reachable in ASLR contextELF64NoNoneReachable
gt-0009Reachable through shared libraryELF64NoNoneReachable
gt-0010Reachable via callback registrationELF64NoNoneReachable

Category B: Unreachable Sinks (10 samples)

IDDescriptionFormatStrippedObfuscationExpected Reason
gt-0011Dead code (never called)ELF64NoNoneno-caller
gt-0012Guarded by impossible conditionELF64NoNonedead-branch
gt-0013Linked but not usedELF64NoNoneunused-import
gt-0014Behind disabled feature flagELF64NoNoneconfig-disabled
gt-0015Requires privilege escalationELF64NoNoneprivilege-gate
gt-0016Behind authentication checkELF64NoNoneauth-gate
gt-0017Unreachable with CFI enabledELF64NoNonecfi-prevented
gt-0018Optimized away by compilerELF64NoNonedce-eliminated
gt-0019In unreachable exception handlerELF64NoNoneexception-only
gt-0020Test-only code not in productionELF64NoNonetest-code-only

Metrics

Primary Metrics

MetricDefinitionTarget
PrecisionTP / (TP + FP)≥ 95%
RecallTP / (TP + FN)≥ 90%
F1 Score2 × (Precision × Recall) / (Precision + Recall)≥ 92%
TTFRPTime-to-First-Reachable-Path (ms)p95 < 500ms
Deterministic ReplayIdentical proofs across runs100%

Regression Gates

CI gates that fail the build:


CI Integration

Benchmark Job

# .gitea/workflows/reachability-bench.yaml
name: Reachability Benchmark
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 2 * * *'  # Nightly

jobs:
  benchmark:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      
      - name: Run corpus benchmark
        run: |
          stellaops bench run \
            --corpus datasets/reachability/ground-truth/ \
            --output bench/results/$(date +%Y%m%d).json \
            --baseline bench/baselines/current.json
      
      - name: Check regression gates
        run: |
          stellaops bench check \
            --results bench/results/$(date +%Y%m%d).json \
            --baseline bench/baselines/current.json \
            --precision-threshold 0.95 \
            --recall-threshold 0.90 \
            --determinism-threshold 1.0
      
      - name: Post results to PR
        if: github.event_name == 'pull_request'
        run: |
          stellaops bench report \
            --results bench/results/$(date +%Y%m%d).json \
            --baseline bench/baselines/current.json \
            --format markdown > bench-report.md
          # Post to PR via API

Result Schema

{
  "runId": "bench-20251217-001",
  "timestamp": "2025-12-17T02:00:00Z",
  "corpusVersion": "1.0.0",
  "scannerVersion": "1.3.0",
  "metrics": {
    "precision": 0.96,
    "recall": 0.91,
    "f1": 0.935,
    "ttfrp_p50_ms": 120,
    "ttfrp_p95_ms": 380,
    "deterministicReplay": 1.0
  },
  "samples": [
    {
      "sampleId": "gt-0001",
      "sinkId": "sink-001",
      "expected": "reachable",
      "actual": "reachable",
      "pathFound": ["main", "process_input", "parse_data", "vulnerable_function"],
      "proofHash": "sha256:abc123...",
      "ttfrpMs": 95
    }
  ],
  "regressions": [],
  "improvements": []
}

Corpus Maintenance

Adding New Samples

  1. Create sample binary with known sink reachability
  2. Write sample.manifest.json with ground-truth annotations
  3. Place in datasets/reachability/ground-truth/{category}/
  4. Update corpus version in datasets/reachability/corpus.json
  5. Run baseline update: stellaops bench baseline update

Updating Baselines

When scanner improvements are validated:

stellaops bench baseline update \
  --results bench/results/latest.json \
  --output bench/baselines/current.json

Sample Categories