ReachabilityAnalysis that proves whether vulnerable code is actually called by your application — filtering out false positives from scanner noise as Evidence

What blocks shipping — reachable, unfixed, policy-relevant exposure first.

The long tail is one filter away.

~85% of critical container vulnerabilities are in inactive code (Sysdig 2024 Container Security Report). Reachability asks whether a path in your image reaches the vulnerable function, and signs a proof for every verdict — kept or removed.

The working set

Seven findings enter the working set in the screen below. One blocks: it is reachable and unfixed. The other six are unfixed but not shown reachable — they stay in the set, ranked lower, never hidden.

blocking = reachable × unfixed × policy-relevant

Stella Ops Exposure screen: a working set of seven findings, one marked blocking with a REACHABLE state, the rest held with NOT OBSERVED states
Exposure screen, Stella Ops console with sample estate. NOT OBSERVED is not "not vulnerable" — unknowns stay visible until evidence says otherwise.

REACHABLE

An executable path from an entrypoint to the vulnerable symbol is evidenced — by static call graph, binary symbol match, or a runtime probe hit.

NOT OBSERVED

No executable path was found with the evidence collected so far. That is a statement about the evidence, not about the vulnerability. The finding keeps its place in the working set.

Two rankings, one dataset

The same working set serves two jobs. Switching between them changes what sorts to the top — nothing enters or leaves.

Ship

Ranks by what blocks this release: reachable, unfixed, policy-relevant exposure first.

Secure

Ranks by total exposure across the estate, including findings that will never gate a release.

It changes ranking and emphasis, never the data.

Where the evidence comes from

Static analysis produces the verdict on every scan. Binary symbols and runtime facts add depth when you want it. CVECommon Vulnerabilities and Exposures - a unique identifier for a publicly known security vulnerability

Layer 1

Static Call-Graph Analysis

Builds a call graph from compiled bytecode and from source, then traces paths from your entrypoints to the functions an advisory names.

  • • Call-graph languages: Go, Java, C#/.NET, JavaScript and TypeScript, Python, Rust, PHP, Ruby. One language is analysed per image. Other ecosystems land in the unknown bucket — scored, not skipped.
  • • Offline extraction is narrower: building a call graph from a source tree in the CLI supports Go and Rust only, and uses the lexical tier — the SSA toolchain ships inside the scanner worker. Other languages are analysed by the scan pipeline, which the CLI consumes as a pre-extracted call graph.
  • • Python, JavaScript/TypeScript, Rust, PHP and Ruby are analysed from source text, and every edge carries its confidence so you can see which tier produced a verdict
  • • Reflection, dynamic invocation and virtual dispatch beyond known implementations are not modelled — every result states this limit
Layer 2

Binary Symbol Analysis

A CLI lane for native code with no source to read: ELF symbol tables and DWARF function names, x86, x64 and ARM64. Its findings stand on their own, separate from a scan verdict.

  • • ELF symbol tables and DWARF function names
  • • x86, x64 and ARM64 disassembly. Debug info is read from DWARF only — no PDB
Layer 3

Runtime eBPFExtended Berkeley Packet Filter — a Linux kernel technology that runs sandboxed programs for high-performance observability and runtime analysis without kernel modules Probes

Feed real execution data in and Stella Ops verifies it and seals it as the strongest reachability evidence there is. You run the probes; RC1 ships the ingest path.

  • • Tetragon-based eBPFExtended Berkeley Packet Filter — a Linux kernel technology that runs sandboxed programs for high-performance observability and runtime analysis without kernel modules instrumentation
  • • Records symbol_id, code_id, hit_count, loader_base
  • • Privacy-preserving: no argument values captured

Each verdict is packaged as a DSSE-signed proof that binds the finding to the executable path it was judged on. Where no path could be analysed, the finding is reported as unknown rather than cleared. DSSEDead Simple Signing Envelope - a simple, flexible standard for signing arbitrary data with cryptographic signatures

Unknowns as First-Class State

When analysis cannot determine reachability, the uncertainty is tracked explicitly — not hidden or silently assumed safe.

ReachabilityAnalysis that proves whether vulnerable code is actually called by your application — filtering out false positives from scanner noise BucketDefault Weight
reachable:proven1.0
reachable:likely0.85
not-observed0.0

Higher means more risk, not more confidence: the weight scales a finding's risk score. Runtime confirmation does not replace the path proof — it raises the confidence attached to the verdict. Where the analyzer observed no path at all, Stella Ops reports not observed with a signed coverage statement, never “unreachable”: observing no path is not proof that none exists.

Policy recommendation: treat unknown as a first-class verdict, set explicit thresholds per severity, and log reviewer override reasons in the evidence bundle.

Where VEX statements enter

Issuer VEX statements join the same evidence graph, normalized to five statuses — not_affected, affected, fixed, under_investigation, unknown — so "under investigation" is a state with consequences, not a footnote. VEXVulnerability Exploitability eXchange - machine-readable statements about whether vulnerabilities are actually exploitable in your context

not_affected affected fixed under_investigation unknown

Multiple issuers can speak about the same component. When they disagree, trust-weighted conflict resolution records the disagreement as a conflict — nothing is averaged, and no issuer silently wins.

How SBOM and VEX evidence is merged →

KEV and EPSS participate — they do not decide

CISA KEV listings and EPSS scores are advisory-level exploit signals. They raise a finding's rank and urgency inside the working set. KEVKnown Exploited Vulnerabilities - CISA's catalog of vulnerabilities actively exploited in the wild EPSSExploit Prediction Scoring System - a probability score (0-100%) predicting how likely a vulnerability is to be exploited in the wild

Exploit signals attach at the advisory level, not at the finding level. Open a CVECommon Vulnerabilities and Exposures - a unique identifier for a publicly known security vulnerability to read its advisory-level exploit data: the KEVKnown Exploited Vulnerabilities - CISA's catalog of vulnerabilities actively exploited in the wild listing and the EPSSExploit Prediction Scoring System - a probability score (0-100%) predicting how likely a vulnerability is to be exploited in the wild score belong to the advisory, and they read the same for every service that carries the affected component.

They are not reachability evidence. A KEV entry on code your service never loads changes emphasis, not the verdict — unless your policy says known-exploited findings block regardless. Two rule classes can block, and they are independent: a CVE denylist ignores reachability entirely, while a reachability rule blocks only on a proven path — reachable:likely and unknown never block through it, whatever states the policy lists.

A policy gate can combine both kinds of answer in one rule: reachability state together with EPSSExploit Prediction Scoring System - a probability score (0-100%) predicting how likely a vulnerability is to be exploited in the wild, KEVKnown Exploited Vulnerabilities - CISA's catalog of vulnerabilities actively exploited in the wild, and CVSSCommon Vulnerability Scoring System - a severity rating from 0-10 indicating how critical a vulnerability is thresholds. "Known-exploited and reachable" and "known-exploited regardless of reachability" are both expressible; which one you enforce is your policy, not a default we pick for you.

Versus a scanner in CI

A scanner answers "what is in this image right now". Necessary — and not sufficient for a release decision.

What a scanner run gives you

  • • A finding list per image, regenerated from scratch on every run
  • • Severity taken from the advisory, not from your call graph
  • • Suppressions in ignore files, with no signed record of who accepted what

What Stella Ops adds

  • • Findings joined across 38 active advisory sources, then ranked by reachability
  • • A DSSE-signed, replayable proof for every verdict — including the removed ones
  • • The verdict feeds the release gate, and Watch keeps comparing the running digest against the approved one after deploy

What Stella Ops does not do

Trivy covers Git repositories, VMs, and Kubernetes targets, plus misconfiguration and secret scanning. Stella Ops does not. Its scope is container images and filesystem snapshots, with signed, replayable evidence for each verdict.

Full comparisons: Stella Ops vs Trivy | Stella Ops vs Grype

Implementation: node hash joins

ReachabilityAnalysis that proves whether vulnerable code is actually called by your application — filtering out false positives from scanner noise evidence is content-addressed for deduplication and verification. Node hashes enable efficient diffing between versions. Node Hash SHA256(normalize(purl) + ":" + normalize(symbol)) Path Hash SHA256(entryNodeHash + ":" + joinedIntermediateHashes + ":" + sinkNodeHash) Top-K significant paths are preserved in the evidence bundle. Paths are ranked by execution frequency (from runtime) or call depth (from static).
Read more

ReachabilityAnalysis that proves whether vulnerable code is actually called by your application — filtering out false positives from scanner noise evidence is content-addressed for deduplication and verification. Node hashes enable efficient diffing between versions.

Node Hash

SHA256(normalize(purl) + ":" + normalize(symbol))

Path Hash

SHA256(entryNodeHash + ":" + joinedIntermediateHashes + ":" + sinkNodeHash)

Top-K significant paths are preserved in the evidence bundle. Paths are ranked by execution frequency (from runtime) or call depth (from static).

Implementation: signed proofs

Every reachability analysis produces a cryptographically signed proof stored in content-addressed storage. DSSE?Dead Simple Signing Envelope - a simple, flexible standard for signing arbitrary data with cryptographic signatures DSSE envelope with in-toto SLSA predicate format Verifiable by auditors without network access Deterministic replay produces bit-identical results Graph and traces archived for offline verification Content-Addressed Storage Paths cas://reachability_graphs/<hh>/<sha>.tar.zst cas://runtime_traces/<hh>/<sha>.tar.zst
Read more

Every reachability analysis produces a cryptographically signed proof stored in content-addressed storage. DSSEDead Simple Signing Envelope - a simple, flexible standard for signing arbitrary data with cryptographic signatures

  • DSSE envelope with in-toto SLSA predicate format
  • Verifiable by auditors without network access
  • Deterministic replay produces bit-identical results
  • Graph and traces archived for offline verification

Content-Addressed Storage Paths

cas://reachability_graphs/<hh>/<sha>.tar.zst

cas://runtime_traces/<hh>/<sha>.tar.zst

Held to a published ground truth

The reachability classifier is held to a labeled corpus that ships in the public source tree: eight minimal services across Java, Node.js, Python, Go, .NET, Ruby, Rust and PHP, each with a labels file stating the expected tier — from R0, not reachable in that service, to R4, reachable from the entrypoint — and the rationale for it, per CVE.

The same tree carries the harness that scores classifications per tier — precision and recall, not a single blended number. Because the corpus, the labels and the tier contract are public, you do not have to take our reading of them: scan the same ground truth with your own installation and compare what it reports against the published expected answers.

How to run that comparison is step 2.1 of the evaluation pilot →

Implementation: eBPF probes

Stella Ops accepts runtime execution facts over a streaming ingest endpoint, and treats them as the strongest reachability evidence there is. RC1 does not ship the collector: the Tetragon-based probes are instrumentation you run, and reachability works without them from the static and binary layers. Captured Probe Data symbol_id: canonical symbol identifier code_id: code section identifier hit_count: execution frequency loader_base: memory base address cas_uri: content-addressed reference Probes submit runtime facts to POST /signals/runtime-facts/ndjson as streaming NDJSON. Each observation carries the CAS URI for the underlying artifact.
Read more

Stella Ops accepts runtime execution facts over a streaming ingest endpoint, and treats them as the strongest reachability evidence there is. RC1 does not ship the collector: the Tetragon-based probes are instrumentation you run, and reachability works without them from the static and binary layers.

Captured Probe Data

symbol_id: canonical symbol identifier

code_id: code section identifier

hit_count: execution frequency

loader_base: memory base address

cas_uri: content-addressed reference

Probes submit runtime facts to POST /signals/runtime-facts/ndjson as streaming NDJSON. Each observation carries the CAS URI for the underlying artifact.

Start with your own working set

Point Stella Ops at an image you ship today and read the verdicts it signs. If reachability removes less than it claims, you will see that too — every removal carries its proof.

Free tier: 3 environments and up to 100 new-digest scans per rolling 24 h, self-hosted. v1.0-RC1, release candidate.