Add SBOM, symbols, traces, and VEX files for CVE-2022-21661 SQLi case
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images. - Added symbols.json detailing function entry and sink points in the WordPress code. - Included runtime traces for function calls in both reachable and unreachable scenarios. - Developed OpenVEX files indicating vulnerability status and justification for both cases. - Updated README for evaluator harness to guide integration with scanner output.
This commit is contained in:
15
tests/reachability/README.md
Normal file
15
tests/reachability/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Reachability Fixture Harness
|
||||
|
||||
This directory carries the reachbench fixture packs used by Sprint 201 to validate reachability explainability.
|
||||
|
||||
- `fixtures/reachbench-2025-expanded/` contains 24 multi-language cases with reachable and unreachable variants, SBOMs, callgraphs, runtime traces, and DSSE envelopes.
|
||||
- `StellaOps.Reachability.FixtureTests` provides lightweight guard rails that ensure each case keeps the expected files, JSON schemas, and ground-truth metadata before the Signals/Scanner reachability pipeline consumes them.
|
||||
|
||||
## Running the fixture tests
|
||||
|
||||
```bash
|
||||
# From the repo root
|
||||
DOTNET_CLI_UI_LANGUAGE=en dotnet test tests/reachability/StellaOps.Reachability.FixtureTests/StellaOps.Reachability.FixtureTests.csproj
|
||||
```
|
||||
|
||||
The tests simply validate the fixtures today; once the reachability engine lands they become the seed harness to replay reachable vs. unreachable scans deterministically.
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Replay.Core;
|
||||
using StellaOps.Scanner.Reachability;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Reachability.FixtureTests;
|
||||
|
||||
public sealed class ReachabilityReplayWriterTests
|
||||
{
|
||||
[Fact]
|
||||
public void AttachEvidence_AppendsGraphsAndTracesDeterministically()
|
||||
{
|
||||
var manifest = new ReplayManifest
|
||||
{
|
||||
Scan = new ReplayScanMetadata { Id = "scan-123", Time = DateTimeOffset.Parse("2025-10-15T10:00:00Z", CultureInfo.InvariantCulture) }
|
||||
};
|
||||
|
||||
var graphs = new List<ReachabilityReplayGraph>
|
||||
{
|
||||
new("static", "cas://graph/B", "ABCDEF", "scanner-jvm", "1.0.0"),
|
||||
new("framework", "cas://graph/A", "abcdef", "scanner-jvm", "1.0.0"),
|
||||
new("static", "cas://graph/B", "ABCDEF", "scanner-jvm", "1.0.0") // duplicate
|
||||
};
|
||||
|
||||
var traces = new List<ReachabilityReplayTrace>
|
||||
{
|
||||
new("zastava", "cas://trace/1", "FFEE", DateTimeOffset.Parse("2025-10-15T09:00:00+02:00", CultureInfo.InvariantCulture)),
|
||||
new("zastava", "cas://trace/2", "ffee", DateTimeOffset.Parse("2025-10-15T09:05:00Z", CultureInfo.InvariantCulture)),
|
||||
new("zastava", "cas://trace/1", "FFEE", DateTimeOffset.Parse("2025-10-15T09:00:00Z", CultureInfo.InvariantCulture)) // duplicate once normalized
|
||||
};
|
||||
|
||||
var writer = new ReachabilityReplayWriter();
|
||||
writer.AttachEvidence(manifest, graphs, traces);
|
||||
|
||||
manifest.Reachability.Should().NotBeNull();
|
||||
manifest.Reachability!.Graphs.Should().HaveCount(2);
|
||||
manifest.Reachability.Graphs[0].CasUri.Should().Be("cas://graph/A");
|
||||
manifest.Reachability.Graphs[0].Sha256.Should().Be("abcdef");
|
||||
manifest.Reachability.Graphs[1].CasUri.Should().Be("cas://graph/B");
|
||||
manifest.Reachability.Graphs[1].Kind.Should().Be("static");
|
||||
|
||||
manifest.Reachability.RuntimeTraces.Should().HaveCount(2);
|
||||
manifest.Reachability.RuntimeTraces[0].RecordedAt.Should().Be(DateTimeOffset.Parse("2025-10-15T07:00:00Z"));
|
||||
manifest.Reachability.RuntimeTraces[0].Sha256.Should().Be("ffee");
|
||||
manifest.Reachability.RuntimeTraces[1].CasUri.Should().Be("cas://trace/2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttachEvidence_DoesNotCreateSectionWhenEmpty()
|
||||
{
|
||||
var manifest = new ReplayManifest();
|
||||
var writer = new ReachabilityReplayWriter();
|
||||
|
||||
writer.AttachEvidence(manifest, Array.Empty<ReachabilityReplayGraph>(), Array.Empty<ReachabilityReplayTrace>());
|
||||
|
||||
manifest.Reachability.Should().BeNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Reachability.FixtureTests;
|
||||
|
||||
public class ReachbenchFixtureTests
|
||||
{
|
||||
private static readonly string RepoRoot = LocateRepoRoot();
|
||||
private static readonly string FixtureRoot = Path.Combine(
|
||||
RepoRoot, "tests", "reachability", "fixtures", "reachbench-2025-expanded");
|
||||
private static readonly string CasesRoot = Path.Combine(FixtureRoot, "cases");
|
||||
|
||||
[Fact]
|
||||
public void IndexListsAllCases()
|
||||
{
|
||||
Directory.Exists(FixtureRoot).Should().BeTrue("reachbench fixtures should exist under tests/reachability/fixtures");
|
||||
File.Exists(Path.Combine(FixtureRoot, "INDEX.json")).Should().BeTrue("the reachbench index must be present");
|
||||
|
||||
using var indexStream = File.OpenRead(Path.Combine(FixtureRoot, "INDEX.json"));
|
||||
using var document = JsonDocument.Parse(indexStream);
|
||||
var names = new List<string>();
|
||||
var found = false;
|
||||
JsonElement casesElement = default;
|
||||
foreach (var property in document.RootElement.EnumerateObject())
|
||||
{
|
||||
names.Add(property.Name);
|
||||
if (property.NameEquals("cases"))
|
||||
{
|
||||
casesElement = property.Value;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
found.Should().BeTrue($"INDEX.json should contain 'cases'. Properties present: {string.Join(",", names)}");
|
||||
casesElement.ValueKind.Should().Be(JsonValueKind.Array);
|
||||
casesElement.GetArrayLength().Should().BeGreaterOrEqualTo(20, "expanded pack should carry broad coverage");
|
||||
|
||||
foreach (var entry in casesElement.EnumerateArray())
|
||||
{
|
||||
var id = entry.GetProperty("id").GetString();
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
var rel = entry.TryGetProperty("path", out var relProp)
|
||||
? relProp.GetString()
|
||||
: Path.Combine("cases", id!);
|
||||
rel.Should().NotBeNullOrEmpty();
|
||||
var path = Path.Combine(FixtureRoot, rel!);
|
||||
Directory.Exists(path).Should().BeTrue($"case '{id}' folder '{rel}' should exist");
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> CaseVariantData()
|
||||
{
|
||||
foreach (var caseDir in Directory.EnumerateDirectories(CasesRoot))
|
||||
{
|
||||
var caseId = Path.GetFileName(caseDir);
|
||||
yield return new object[] { caseId!, Path.Combine(caseDir, "images", "reachable") };
|
||||
yield return new object[] { caseId!, Path.Combine(caseDir, "images", "unreachable") };
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CaseVariantData))]
|
||||
public void CaseVariantContainsExpectedArtifacts(string caseId, string variantPath)
|
||||
{
|
||||
Directory.Exists(variantPath).Should().BeTrue();
|
||||
|
||||
var requiredFiles = new[]
|
||||
{
|
||||
"manifest.json",
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json",
|
||||
"attestation.dsse.json"
|
||||
};
|
||||
|
||||
foreach (var file in requiredFiles)
|
||||
{
|
||||
File.Exists(Path.Combine(variantPath, file)).Should().BeTrue($"{caseId}:{Path.GetFileName(variantPath)} missing {file}");
|
||||
}
|
||||
|
||||
var truthPath = Path.Combine(variantPath, "reachgraph.truth.json");
|
||||
using var truthStream = File.OpenRead(truthPath);
|
||||
using var truthDoc = JsonDocument.Parse(truthStream);
|
||||
truthDoc.RootElement.GetProperty("schema_version").GetString().Should().NotBeNullOrEmpty();
|
||||
truthDoc.RootElement.GetProperty("paths").ValueKind.Should().Be(JsonValueKind.Array);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CaseVariantData))]
|
||||
public void CaseGroundTruthMatchesVariants(string caseId, string variantPath)
|
||||
{
|
||||
var caseJsonPath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(variantPath))!, "case.json");
|
||||
File.Exists(caseJsonPath).Should().BeTrue();
|
||||
|
||||
using var caseStream = File.OpenRead(caseJsonPath);
|
||||
using var caseDoc = JsonDocument.Parse(caseStream);
|
||||
var groundTruth = caseDoc.RootElement.GetProperty("ground_truth");
|
||||
var variantKey = variantPath.EndsWith("reachable", StringComparison.OrdinalIgnoreCase)
|
||||
? "reachable_variant"
|
||||
: "unreachable_variant";
|
||||
|
||||
var variant = groundTruth.GetProperty(variantKey);
|
||||
variant.GetProperty("status").GetString().Should().NotBeNullOrEmpty($"{caseId}:{variantKey} should set status");
|
||||
variant.TryGetProperty("evidence", out var evidence).Should().BeTrue($"{caseId}:{variantKey} should define evidence");
|
||||
evidence.TryGetProperty("paths", out var pathsProp).Should().BeTrue();
|
||||
pathsProp.ValueKind.Should().Be(JsonValueKind.Array);
|
||||
}
|
||||
|
||||
private static string LocateRepoRoot()
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (current != null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(current.FullName, "Directory.Build.props")))
|
||||
{
|
||||
return current.FullName;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Cannot locate repository root (missing Directory.Build.props).");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.7.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="10.0.0-preview.7.24405.7" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\\..\\fixtures\\**\\*">
|
||||
<Link>fixtures\\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Scanner\__Libraries\StellaOps.Scanner.Reachability\StellaOps.Scanner.Reachability.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\__Libraries\StellaOps.Replay.Core\StellaOps.Replay.Core.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Replay.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Replay.Core.Tests;
|
||||
|
||||
public sealed class ReplayManifestExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddsReachabilityEvidence()
|
||||
{
|
||||
var manifest = new ReplayManifest
|
||||
{
|
||||
Scan = new ReplayScanMetadata { Id = "scan-1" }
|
||||
};
|
||||
|
||||
manifest.AddReachabilityGraph(new ReplayReachabilityGraphReference
|
||||
{
|
||||
Kind = "static",
|
||||
Analyzer = "scanner/java",
|
||||
CasUri = "cas://replay/graph",
|
||||
Sha256 = "abc",
|
||||
Version = "1.0"
|
||||
});
|
||||
|
||||
manifest.AddReachabilityTrace(new ReplayReachabilityTraceReference
|
||||
{
|
||||
Source = "zastava",
|
||||
CasUri = "cas://replay/trace",
|
||||
Sha256 = "def"
|
||||
});
|
||||
|
||||
manifest.Reachability.Should().NotBeNull();
|
||||
manifest.Reachability!.Graphs.Should().HaveCount(1);
|
||||
manifest.Reachability.RuntimeTraces.Should().HaveCount(1);
|
||||
|
||||
var json = JsonSerializer.Serialize(manifest);
|
||||
json.Should().Contain("\"reachability\"");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.7.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../src/__Libraries/StellaOps.Replay.Core/StellaOps.Replay.Core.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,227 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Scanner.Reachability;
|
||||
using StellaOps.Signals.Models;
|
||||
using StellaOps.Signals.Options;
|
||||
using StellaOps.Signals.Parsing;
|
||||
using StellaOps.Signals.Persistence;
|
||||
using StellaOps.Signals.Services;
|
||||
using StellaOps.Signals.Storage;
|
||||
using StellaOps.Signals.Storage.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.ScannerSignals.IntegrationTests;
|
||||
|
||||
public sealed class ScannerToSignalsReachabilityTests
|
||||
{
|
||||
private static readonly string RepoRoot = LocateRepoRoot();
|
||||
private static readonly string FixtureRoot = Path.Combine(RepoRoot, "tests", "reachability", "fixtures", "reachbench-2025-expanded", "cases");
|
||||
|
||||
[Fact]
|
||||
public async Task ScannerBuilderFeedsSignalsScoringPipeline()
|
||||
{
|
||||
var caseId = "java-log4j-CVE-2021-44228-log4shell";
|
||||
var variant = "reachable";
|
||||
var variantPath = Path.Combine(FixtureRoot, caseId, "images", variant);
|
||||
Directory.Exists(variantPath).Should().BeTrue();
|
||||
|
||||
var builder = ReachabilityGraphBuilder.FromFixture(variantPath);
|
||||
var artifactJson = builder.BuildJson(indented: false);
|
||||
var parser = new SimpleJsonCallgraphParser("java");
|
||||
var parserResolver = new StaticParserResolver(new Dictionary<string, ICallgraphParser>
|
||||
{
|
||||
["java"] = parser
|
||||
});
|
||||
var artifactStore = new InMemoryCallgraphArtifactStore();
|
||||
var callgraphRepo = new InMemoryCallgraphRepository();
|
||||
var ingestionService = new CallgraphIngestionService(
|
||||
parserResolver,
|
||||
artifactStore,
|
||||
callgraphRepo,
|
||||
Options.Create(new SignalsOptions()),
|
||||
TimeProvider.System,
|
||||
NullLogger<CallgraphIngestionService>.Instance);
|
||||
|
||||
var request = new CallgraphIngestRequest(
|
||||
Language: "java",
|
||||
Component: caseId,
|
||||
Version: variant,
|
||||
ArtifactContentType: "application/json",
|
||||
ArtifactFileName: "callgraph.static.json",
|
||||
ArtifactContentBase64: Convert.ToBase64String(Encoding.UTF8.GetBytes(artifactJson)),
|
||||
Metadata: null);
|
||||
|
||||
var ingestResponse = await ingestionService.IngestAsync(request, CancellationToken.None);
|
||||
ingestResponse.CallgraphId.Should().NotBeNullOrWhiteSpace();
|
||||
|
||||
var scoringService = new ReachabilityScoringService(
|
||||
callgraphRepo,
|
||||
new InMemoryReachabilityFactRepository(),
|
||||
TimeProvider.System,
|
||||
NullLogger<ReachabilityScoringService>.Instance);
|
||||
|
||||
var truth = JsonDocument.Parse(File.ReadAllText(Path.Combine(variantPath, "reachgraph.truth.json"))).RootElement;
|
||||
var entryPoints = truth.GetProperty("paths").EnumerateArray()
|
||||
.Select(path => path[0].GetString()!)
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
var targets = truth.GetProperty("sinks").EnumerateArray().Select(s => s.GetProperty("sid").GetString()!).ToList();
|
||||
|
||||
var recomputeRequest = new ReachabilityRecomputeRequest
|
||||
{
|
||||
CallgraphId = ingestResponse.CallgraphId,
|
||||
Subject = new ReachabilitySubject
|
||||
{
|
||||
ScanId = $"{caseId}:{variant}",
|
||||
Component = caseId,
|
||||
Version = variant
|
||||
},
|
||||
EntryPoints = entryPoints,
|
||||
Targets = targets,
|
||||
RuntimeHits = ReadRuntimeHits(Path.Combine(variantPath, "traces.runtime.jsonl"))
|
||||
};
|
||||
|
||||
var fact = await scoringService.RecomputeAsync(recomputeRequest, CancellationToken.None);
|
||||
fact.States.Should().ContainSingle(state => state.Target == targets[0] && state.Reachable);
|
||||
}
|
||||
|
||||
private static List<string> ReadRuntimeHits(string tracePath)
|
||||
{
|
||||
var hits = new List<string>();
|
||||
if (!File.Exists(tracePath))
|
||||
{
|
||||
return hits;
|
||||
}
|
||||
|
||||
foreach (var line in File.ReadLines(tracePath))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using var doc = JsonDocument.Parse(line);
|
||||
if (doc.RootElement.TryGetProperty("sid", out var sid))
|
||||
{
|
||||
hits.Add(sid.GetString()!);
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
|
||||
private sealed class StaticParserResolver : ICallgraphParserResolver
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, ICallgraphParser> parsers;
|
||||
|
||||
public StaticParserResolver(IReadOnlyDictionary<string, ICallgraphParser> parsers)
|
||||
{
|
||||
this.parsers = parsers;
|
||||
}
|
||||
|
||||
public ICallgraphParser Resolve(string language)
|
||||
{
|
||||
if (parsers.TryGetValue(language, out var parser))
|
||||
{
|
||||
return parser;
|
||||
}
|
||||
|
||||
throw new CallgraphParserNotFoundException(language);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class InMemoryCallgraphRepository : ICallgraphRepository
|
||||
{
|
||||
private readonly Dictionary<string, CallgraphDocument> storage = new(StringComparer.Ordinal);
|
||||
|
||||
public Task<CallgraphDocument?> GetByIdAsync(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
storage.TryGetValue(id, out var document);
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public Task<CallgraphDocument> UpsertAsync(CallgraphDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(document.Id))
|
||||
{
|
||||
document.Id = ObjectId.GenerateNewId().ToString();
|
||||
}
|
||||
|
||||
storage[document.Id] = document;
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class InMemoryReachabilityFactRepository : IReachabilityFactRepository
|
||||
{
|
||||
private readonly Dictionary<string, ReachabilityFactDocument> storage = new(StringComparer.Ordinal);
|
||||
|
||||
public Task<ReachabilityFactDocument?> GetBySubjectAsync(string subjectKey, CancellationToken cancellationToken)
|
||||
{
|
||||
storage.TryGetValue(subjectKey, out var document);
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public Task<ReachabilityFactDocument> UpsertAsync(ReachabilityFactDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
storage[document.SubjectKey] = document;
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class InMemoryCallgraphArtifactStore : ICallgraphArtifactStore
|
||||
{
|
||||
public async Task<StoredCallgraphArtifact> SaveAsync(CallgraphArtifactSaveRequest request, Stream content, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
ArgumentNullException.ThrowIfNull(content);
|
||||
|
||||
await using var buffer = new MemoryStream();
|
||||
await content.CopyToAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = buffer.ToArray();
|
||||
var computedHash = Convert.ToHexString(SHA256.HashData(bytes));
|
||||
|
||||
if (content.CanSeek)
|
||||
{
|
||||
content.Position = 0;
|
||||
}
|
||||
|
||||
if (!computedHash.Equals(request.Hash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException($"Hash mismatch for {request.FileName}: expected {request.Hash} but computed {computedHash}.");
|
||||
}
|
||||
|
||||
return new StoredCallgraphArtifact(
|
||||
Path: $"cas://fixtures/{request.Component}/{request.Version}/{request.FileName}",
|
||||
Length: bytes.Length,
|
||||
Hash: computedHash,
|
||||
ContentType: request.ContentType);
|
||||
}
|
||||
}
|
||||
private static string LocateRepoRoot()
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (current != null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(current.FullName, "Directory.Build.props")))
|
||||
{
|
||||
return current.FullName;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Cannot locate repository root (missing Directory.Build.props).");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.7.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../src/Signals/StellaOps.Signals/StellaOps.Signals.csproj" />
|
||||
<ProjectReference Include="../../../src/Scanner/__Libraries/StellaOps.Scanner.Reachability/StellaOps.Scanner.Reachability.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\fixtures\**\*">
|
||||
<Link>fixtures\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Signals.Models;
|
||||
using StellaOps.Signals.Parsing;
|
||||
using StellaOps.Signals.Persistence;
|
||||
using StellaOps.Signals.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Signals.Reachability.Tests;
|
||||
|
||||
public sealed class ReachabilityScoringTests
|
||||
{
|
||||
private static readonly string RepoRoot = LocateRepoRoot();
|
||||
private static readonly string FixtureRoot = Path.Combine(RepoRoot, "tests", "reachability", "fixtures", "reachbench-2025-expanded", "cases");
|
||||
|
||||
private static readonly (string CaseId, string Variant)[] SampleCases =
|
||||
{
|
||||
("java-log4j-CVE-2021-44228-log4shell", "reachable"),
|
||||
("java-log4j-CVE-2021-44228-log4shell", "unreachable"),
|
||||
("redis-CVE-2022-0543-lua-sandbox-escape", "reachable")
|
||||
};
|
||||
|
||||
public static IEnumerable<object[]> CaseVariants()
|
||||
{
|
||||
foreach (var (caseId, variant) in SampleCases)
|
||||
{
|
||||
var path = Path.Combine(FixtureRoot, caseId, "images", variant);
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
yield return new object[] { caseId, variant };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CaseVariants))]
|
||||
public async Task RecomputedFactsMatchTruthFixtures(string caseId, string variant)
|
||||
{
|
||||
var casePath = Path.Combine(FixtureRoot, caseId);
|
||||
var variantPath = Path.Combine(casePath, "images", variant);
|
||||
var truth = JsonDocument.Parse(File.ReadAllText(Path.Combine(variantPath, "reachgraph.truth.json"))).RootElement;
|
||||
var sinks = truth.GetProperty("sinks").EnumerateArray().Select(x => x.GetProperty("sid").GetString()!).ToList();
|
||||
var entryPoints = truth.GetProperty("paths").EnumerateArray()
|
||||
.Select(path => path[0].GetString()!)
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var callgraph = await LoadCallgraphAsync(caseId, variant, variantPath);
|
||||
var callgraphRepo = new InMemoryCallgraphRepository(callgraph);
|
||||
var factRepo = new InMemoryReachabilityFactRepository();
|
||||
var scoringService = new ReachabilityScoringService(callgraphRepo, factRepo, TimeProvider.System, NullLogger<ReachabilityScoringService>.Instance);
|
||||
|
||||
var request = BuildRequest(casePath, variant, sinks, entryPoints);
|
||||
request.CallgraphId = callgraph.Id;
|
||||
|
||||
var fact = await scoringService.RecomputeAsync(request, CancellationToken.None);
|
||||
fact.States.Should().HaveCount(sinks.Count);
|
||||
|
||||
var expectedReachable = variant == "reachable";
|
||||
foreach (var sink in sinks)
|
||||
{
|
||||
var state = fact.States.Single(s => s.Target == sink);
|
||||
state.Reachable.Should().Be(expectedReachable, $"{caseId}:{variant} expected reachable={expectedReachable}");
|
||||
if (expectedReachable)
|
||||
{
|
||||
state.Path.Should().NotBeEmpty();
|
||||
state.Evidence.RuntimeHits.Should().NotBeEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Path.Should().BeEmpty();
|
||||
state.Evidence.BlockedEdges.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ReachabilityRecomputeRequest BuildRequest(string casePath, string variant, List<string> targets, List<string> entryPoints)
|
||||
{
|
||||
var caseJson = JsonDocument.Parse(File.ReadAllText(Path.Combine(casePath, "case.json"))).RootElement;
|
||||
var variantKey = variant == "reachable" ? "reachable_variant" : "unreachable_variant";
|
||||
var variantNode = caseJson.GetProperty("ground_truth").GetProperty(variantKey);
|
||||
|
||||
var blockedEdges = new List<ReachabilityBlockedEdge>();
|
||||
if (variantNode.TryGetProperty("evidence", out var evidence) && evidence.TryGetProperty("blocked_edges", out var blockedArray))
|
||||
{
|
||||
foreach (var item in blockedArray.EnumerateArray())
|
||||
{
|
||||
var parts = item.GetString()?.Split("->", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts is { Length: 2 })
|
||||
{
|
||||
blockedEdges.Add(new ReachabilityBlockedEdge { From = parts[0], To = parts[1] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var runtimeHits = new List<string>();
|
||||
var tracePath = Path.Combine(casePath, "images", variant, "traces.runtime.jsonl");
|
||||
if (File.Exists(tracePath))
|
||||
{
|
||||
foreach (var line in File.ReadLines(tracePath))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using var doc = JsonDocument.Parse(line);
|
||||
if (doc.RootElement.TryGetProperty("sid", out var sidProp))
|
||||
{
|
||||
runtimeHits.Add(sidProp.GetString()!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ReachabilityRecomputeRequest
|
||||
{
|
||||
Subject = new ReachabilitySubject
|
||||
{
|
||||
ScanId = $"{Path.GetFileName(casePath)}:{variant}",
|
||||
Component = Path.GetFileName(casePath),
|
||||
Version = variant
|
||||
},
|
||||
EntryPoints = entryPoints,
|
||||
Targets = targets,
|
||||
RuntimeHits = runtimeHits,
|
||||
BlockedEdges = blockedEdges
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task<CallgraphDocument> LoadCallgraphAsync(string caseId, string variant, string variantPath)
|
||||
{
|
||||
var parser = new SimpleJsonCallgraphParser("fixture");
|
||||
var nodes = new Dictionary<string, CallgraphNode>(StringComparer.Ordinal);
|
||||
var edges = new List<CallgraphEdge>();
|
||||
|
||||
foreach (var fileName in new[] { "callgraph.static.json", "callgraph.framework.json" })
|
||||
{
|
||||
var path = Path.Combine(variantPath, fileName);
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await using var stream = File.OpenRead(path);
|
||||
var result = await parser.ParseAsync(stream, CancellationToken.None);
|
||||
foreach (var node in result.Nodes)
|
||||
{
|
||||
nodes[node.Id] = node;
|
||||
}
|
||||
|
||||
edges.AddRange(result.Edges);
|
||||
}
|
||||
|
||||
return new CallgraphDocument
|
||||
{
|
||||
Id = ObjectId.GenerateNewId().ToString(),
|
||||
Language = "fixture",
|
||||
Component = caseId,
|
||||
Version = variant,
|
||||
Nodes = nodes.Values.ToList(),
|
||||
Edges = edges,
|
||||
Artifact = new CallgraphArtifactMetadata
|
||||
{
|
||||
Path = $"cas://fixtures/{caseId}/{variant}",
|
||||
Hash = "stub",
|
||||
ContentType = "application/json",
|
||||
Length = 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private sealed class InMemoryCallgraphRepository : ICallgraphRepository
|
||||
{
|
||||
private readonly Dictionary<string, CallgraphDocument> storage;
|
||||
|
||||
public InMemoryCallgraphRepository(CallgraphDocument document)
|
||||
{
|
||||
storage = new Dictionary<string, CallgraphDocument>(StringComparer.Ordinal)
|
||||
{
|
||||
[document.Id] = document
|
||||
};
|
||||
}
|
||||
|
||||
public Task<CallgraphDocument> UpsertAsync(CallgraphDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
storage[document.Id] = document;
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public Task<CallgraphDocument?> GetByIdAsync(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
storage.TryGetValue(id, out var document);
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class InMemoryReachabilityFactRepository : IReachabilityFactRepository
|
||||
{
|
||||
private readonly Dictionary<string, ReachabilityFactDocument> storage = new(StringComparer.Ordinal);
|
||||
|
||||
public Task<ReachabilityFactDocument?> GetBySubjectAsync(string subjectKey, CancellationToken cancellationToken)
|
||||
{
|
||||
storage.TryGetValue(subjectKey, out var document);
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public Task<ReachabilityFactDocument> UpsertAsync(ReachabilityFactDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
storage[document.SubjectKey] = document;
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
private static string LocateRepoRoot()
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (current != null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(current.FullName, "Directory.Build.props")))
|
||||
{
|
||||
return current.FullName;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Cannot locate repository root (missing Directory.Build.props).");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.7.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../src/Signals/StellaOps.Signals/StellaOps.Signals.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\fixtures\**\*">
|
||||
<Link>fixtures\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
444
tests/reachability/fixtures/reachbench-2025-expanded/INDEX.json
Normal file
444
tests/reachability/fixtures/reachbench-2025-expanded/INDEX.json
Normal file
@@ -0,0 +1,444 @@
|
||||
{
|
||||
"version": "0.1",
|
||||
"generated_at": "2025-11-07T22:40:04Z",
|
||||
"cases": [
|
||||
{
|
||||
"id": "runc-CVE-2024-21626-symlink-breakout",
|
||||
"primary_axis": "container-escape",
|
||||
"tags": [
|
||||
"symlink",
|
||||
"filesystem",
|
||||
"userns"
|
||||
],
|
||||
"languages": [
|
||||
"binary"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 9.0,
|
||||
"references": [
|
||||
"cve:CVE-2024-21626"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "linux-cgroups-CVE-2022-0492-release_agent",
|
||||
"primary_axis": "container-escape",
|
||||
"tags": [
|
||||
"cgroups",
|
||||
"kernel",
|
||||
"priv-esc"
|
||||
],
|
||||
"languages": [
|
||||
"binary"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 9.0,
|
||||
"references": [
|
||||
"cve:CVE-2022-0492"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "glibc-CVE-2023-4911-looney-tunables",
|
||||
"primary_axis": "binary-hybrid",
|
||||
"tags": [
|
||||
"env-vars",
|
||||
"libc",
|
||||
"ldso"
|
||||
],
|
||||
"languages": [
|
||||
"c"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2023-4911"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "curl-CVE-2023-38545-socks5-heap",
|
||||
"primary_axis": "binary-hybrid",
|
||||
"tags": [
|
||||
"networking",
|
||||
"proxy",
|
||||
"heap"
|
||||
],
|
||||
"languages": [
|
||||
"c"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2023-38545"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "openssl-CVE-2022-3602-x509-name-constraints",
|
||||
"primary_axis": "binary-hybrid",
|
||||
"tags": [
|
||||
"x509",
|
||||
"parser",
|
||||
"stack-overflow"
|
||||
],
|
||||
"languages": [
|
||||
"c"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2022-3602"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "openssh-CVE-2024-6387-regreSSHion",
|
||||
"primary_axis": "binary-hybrid",
|
||||
"tags": [
|
||||
"signal-handler",
|
||||
"daemon"
|
||||
],
|
||||
"languages": [
|
||||
"c"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2024-6387"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "redis-CVE-2022-0543-lua-sandbox-escape",
|
||||
"primary_axis": "binary-hybrid",
|
||||
"tags": [
|
||||
"lua",
|
||||
"sandbox",
|
||||
"rce"
|
||||
],
|
||||
"languages": [
|
||||
"c",
|
||||
"lua"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2022-0543"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "java-log4j-CVE-2021-44228-log4shell",
|
||||
"primary_axis": "lang-jvm",
|
||||
"tags": [
|
||||
"jndi",
|
||||
"deserialization",
|
||||
"rce"
|
||||
],
|
||||
"languages": [
|
||||
"java"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 9.8,
|
||||
"references": [
|
||||
"cve:CVE-2021-44228"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "java-spring-CVE-2022-22965-spring4shell",
|
||||
"primary_axis": "lang-jvm",
|
||||
"tags": [
|
||||
"binding",
|
||||
"reflection",
|
||||
"rce"
|
||||
],
|
||||
"languages": [
|
||||
"java"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 9.8,
|
||||
"references": [
|
||||
"cve:CVE-2022-22965"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "java-jackson-CVE-2019-12384-polymorphic-deser",
|
||||
"primary_axis": "lang-jvm",
|
||||
"tags": [
|
||||
"deserialization",
|
||||
"polymorphism"
|
||||
],
|
||||
"languages": [
|
||||
"java"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2019-12384"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dotnet-kestrel-CVE-2023-44487-http2-rapid-reset",
|
||||
"primary_axis": "lang-dotnet",
|
||||
"tags": [
|
||||
"protocol",
|
||||
"http2",
|
||||
"dos"
|
||||
],
|
||||
"languages": [
|
||||
"dotnet"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2023-44487"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dotnet-newtonsoft-deser-TBD",
|
||||
"primary_axis": "lang-dotnet",
|
||||
"tags": [
|
||||
"deserialization",
|
||||
"json",
|
||||
"polymorphic"
|
||||
],
|
||||
"languages": [
|
||||
"dotnet"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": []
|
||||
},
|
||||
{
|
||||
"id": "go-ssh-CVE-2020-9283-keyexchange",
|
||||
"primary_axis": "lang-go",
|
||||
"tags": [
|
||||
"crypto",
|
||||
"handshake"
|
||||
],
|
||||
"languages": [
|
||||
"go"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2020-9283"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "go-gateway-reflection-auth-bypass",
|
||||
"primary_axis": "lang-go",
|
||||
"tags": [
|
||||
"grpc",
|
||||
"reflection",
|
||||
"authz-gap"
|
||||
],
|
||||
"languages": [
|
||||
"go"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": []
|
||||
},
|
||||
{
|
||||
"id": "node-tar-CVE-2021-37713-path-traversal",
|
||||
"primary_axis": "lang-node",
|
||||
"tags": [
|
||||
"path-traversal",
|
||||
"archive-extract"
|
||||
],
|
||||
"languages": [
|
||||
"node"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2021-37713"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "node-express-middleware-order-auth-bypass",
|
||||
"primary_axis": "lang-node",
|
||||
"tags": [
|
||||
"middleware-order",
|
||||
"authz"
|
||||
],
|
||||
"languages": [
|
||||
"node"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": []
|
||||
},
|
||||
{
|
||||
"id": "python-jinja2-CVE-2019-10906-template-injection",
|
||||
"primary_axis": "lang-python",
|
||||
"tags": [
|
||||
"template-injection"
|
||||
],
|
||||
"languages": [
|
||||
"python"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2019-10906"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "python-django-CVE-2019-19844-sqli-like",
|
||||
"primary_axis": "lang-python",
|
||||
"tags": [
|
||||
"sqli",
|
||||
"orm"
|
||||
],
|
||||
"languages": [
|
||||
"python"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2019-19844"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "python-urllib3-dos-regex-TBD",
|
||||
"primary_axis": "lang-python",
|
||||
"tags": [
|
||||
"regex-dos",
|
||||
"parser"
|
||||
],
|
||||
"languages": [
|
||||
"python"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": []
|
||||
},
|
||||
{
|
||||
"id": "php-phpmailer-CVE-2016-10033-rce",
|
||||
"primary_axis": "lang-php",
|
||||
"tags": [
|
||||
"rce",
|
||||
"email"
|
||||
],
|
||||
"languages": [
|
||||
"php"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2016-10033"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "wordpress-core-CVE-2022-21661-sqli",
|
||||
"primary_axis": "lang-php",
|
||||
"tags": [
|
||||
"sqli",
|
||||
"core"
|
||||
],
|
||||
"languages": [
|
||||
"php"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2022-21661"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rails-CVE-2019-5418-file-content-disclosure",
|
||||
"primary_axis": "lang-ruby",
|
||||
"tags": [
|
||||
"path-traversal",
|
||||
"mime"
|
||||
],
|
||||
"languages": [
|
||||
"ruby"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": [
|
||||
"cve:CVE-2019-5418"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rust-axum-header-parsing-TBD",
|
||||
"primary_axis": "lang-rust",
|
||||
"tags": [
|
||||
"parser",
|
||||
"config-sensitive"
|
||||
],
|
||||
"languages": [
|
||||
"rust"
|
||||
],
|
||||
"variants": [
|
||||
"reachable",
|
||||
"unreachable"
|
||||
],
|
||||
"severity_cvss": 7.5,
|
||||
"references": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# ReachBench-2025 Expanded Kit (Skeleton)
|
||||
This is a scaffold containing diverse cases across languages and reach paths. Replace STUBs with real build configs, symbols, and call graphs.
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"id": "curl-CVE-2023-38545-socks5-heap",
|
||||
"cve": "CVE-2023-38545",
|
||||
"description": "STUB: Replace with accurate description and threat model for the specific CVE/case.",
|
||||
"threat_model": {
|
||||
"entry_points": [
|
||||
"STUB: define concrete inputs"
|
||||
],
|
||||
"preconditions": [
|
||||
"STUB: feature flags / modules / protocols enabled"
|
||||
],
|
||||
"privilege_boundary": [
|
||||
"STUB: describe boundary (if any)"
|
||||
]
|
||||
},
|
||||
"ground_truth": {
|
||||
"reachable_variant": {
|
||||
"status": "affected",
|
||||
"evidence": {
|
||||
"symbols": [
|
||||
"sym://curl:curl.c#sink"
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://curl:curl.c#entry",
|
||||
"sym://curl:curl.c#sink"
|
||||
]
|
||||
],
|
||||
"runtime_proof": "traces.runtime.jsonl: lines 1-5"
|
||||
}
|
||||
},
|
||||
"unreachable_variant": {
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"evidence": {
|
||||
"pruning_reason": [
|
||||
"STUB: feature disabled, module absent, or policy denies"
|
||||
],
|
||||
"blocked_edges": [
|
||||
"sym://curl:curl.c#entry -> sym://curl:curl.c#sink"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# curl-CVE-2023-38545-socks5-heap
|
||||
Primary axis: binary-hybrid
|
||||
Tags: networking, proxy, heap
|
||||
Languages: c
|
||||
|
||||
## Variants
|
||||
- reachable: vulnerable function/path is on an executable route.
|
||||
- unreachable: same base image/config with control toggles that prune the path.
|
||||
|
||||
## Entrypoint & Controls (fill in)
|
||||
- entrypoints: e.g., http:/route, grpc method, tcp port, OCI hook
|
||||
- flags: e.g., feature_on=true, middleware_order=bad|good, module_loaded=true|false, LSM=enforcing|permissive
|
||||
|
||||
## Expected ground-truth path(s)
|
||||
See `images/*/reachgraph.truth.json`.
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/curl-CVE-2023-38545-socks5-heap:reachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://curl:curl.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://curl:curl.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://curl:curl.c#entry",
|
||||
"to": "sym://curl:curl.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/curl-CVE-2023-38545-socks5-heap:reachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": true,
|
||||
"POLICY_MODE": "permissive"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://curl:curl.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://curl:curl.c#entry",
|
||||
"sym://curl:curl.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/curl@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/curl.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://curl:curl.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://curl:curl.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://curl:curl.c#entry", "pid": 100}
|
||||
{"ts": 1.005, "event": "call", "sid": "sym://curl:curl.c#sink", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2023-38545",
|
||||
"status": "affected",
|
||||
"justification": "reasoning_provided",
|
||||
"impact_statement": "Function-level path is reachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/curl-CVE-2023-38545-socks5-heap:unreachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://curl:curl.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://curl:curl.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://curl:curl.c#entry",
|
||||
"to": "sym://curl:curl.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/curl-CVE-2023-38545-socks5-heap:unreachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": false,
|
||||
"POLICY_MODE": "enforcing"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://curl:curl.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://curl:curl.c#entry",
|
||||
"sym://curl:curl.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/curl@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/curl.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://curl:curl.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://curl:curl.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://curl:curl.c#entry", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2023-38545",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Pruned by configuration; path unreachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"id": "dotnet-kestrel-CVE-2023-44487-http2-rapid-reset",
|
||||
"cve": "CVE-2023-44487",
|
||||
"description": "STUB: Replace with accurate description and threat model for the specific CVE/case.",
|
||||
"threat_model": {
|
||||
"entry_points": [
|
||||
"STUB: define concrete inputs"
|
||||
],
|
||||
"preconditions": [
|
||||
"STUB: feature flags / modules / protocols enabled"
|
||||
],
|
||||
"privilege_boundary": [
|
||||
"STUB: describe boundary (if any)"
|
||||
]
|
||||
},
|
||||
"ground_truth": {
|
||||
"reachable_variant": {
|
||||
"status": "affected",
|
||||
"evidence": {
|
||||
"symbols": [
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://dotnet:dotnet.c#entry",
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
],
|
||||
"runtime_proof": "traces.runtime.jsonl: lines 1-5"
|
||||
}
|
||||
},
|
||||
"unreachable_variant": {
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"evidence": {
|
||||
"pruning_reason": [
|
||||
"STUB: feature disabled, module absent, or policy denies"
|
||||
],
|
||||
"blocked_edges": [
|
||||
"sym://dotnet:dotnet.c#entry -> sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# dotnet-kestrel-CVE-2023-44487-http2-rapid-reset
|
||||
Primary axis: lang-dotnet
|
||||
Tags: protocol, http2, dos
|
||||
Languages: dotnet
|
||||
|
||||
## Variants
|
||||
- reachable: vulnerable function/path is on an executable route.
|
||||
- unreachable: same base image/config with control toggles that prune the path.
|
||||
|
||||
## Entrypoint & Controls (fill in)
|
||||
- entrypoints: e.g., http:/route, grpc method, tcp port, OCI hook
|
||||
- flags: e.g., feature_on=true, middleware_order=bad|good, module_loaded=true|false, LSM=enforcing|permissive
|
||||
|
||||
## Expected ground-truth path(s)
|
||||
See `images/*/reachgraph.truth.json`.
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/dotnet-kestrel-CVE-2023-44487-http2-rapid-reset:reachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:Startup#Configure",
|
||||
"to": "sym://aspnet:UseEndpoints",
|
||||
"kind": "pipeline"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:dotnet.c#entry",
|
||||
"to": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/dotnet-kestrel-CVE-2023-44487-http2-rapid-reset:reachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": true,
|
||||
"POLICY_MODE": "permissive"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://dotnet:dotnet.c#entry",
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/dotnet@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/dotnet.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://dotnet:dotnet.c#entry", "pid": 100}
|
||||
{"ts": 1.005, "event": "call", "sid": "sym://dotnet:dotnet.c#sink", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2023-44487",
|
||||
"status": "affected",
|
||||
"justification": "reasoning_provided",
|
||||
"impact_statement": "Function-level path is reachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/dotnet-kestrel-CVE-2023-44487-http2-rapid-reset:unreachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:Startup#Configure",
|
||||
"to": "sym://aspnet:UseEndpoints",
|
||||
"kind": "pipeline"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:dotnet.c#entry",
|
||||
"to": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/dotnet-kestrel-CVE-2023-44487-http2-rapid-reset:unreachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": false,
|
||||
"POLICY_MODE": "enforcing"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://dotnet:dotnet.c#entry",
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/dotnet@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/dotnet.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://dotnet:dotnet.c#entry", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2023-44487",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Pruned by configuration; path unreachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"id": "dotnet-newtonsoft-deser-TBD",
|
||||
"cve": "N/A",
|
||||
"description": "STUB: Replace with accurate description and threat model for the specific CVE/case.",
|
||||
"threat_model": {
|
||||
"entry_points": [
|
||||
"STUB: define concrete inputs"
|
||||
],
|
||||
"preconditions": [
|
||||
"STUB: feature flags / modules / protocols enabled"
|
||||
],
|
||||
"privilege_boundary": [
|
||||
"STUB: describe boundary (if any)"
|
||||
]
|
||||
},
|
||||
"ground_truth": {
|
||||
"reachable_variant": {
|
||||
"status": "affected",
|
||||
"evidence": {
|
||||
"symbols": [
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://dotnet:dotnet.c#entry",
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
],
|
||||
"runtime_proof": "traces.runtime.jsonl: lines 1-5"
|
||||
}
|
||||
},
|
||||
"unreachable_variant": {
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"evidence": {
|
||||
"pruning_reason": [
|
||||
"STUB: feature disabled, module absent, or policy denies"
|
||||
],
|
||||
"blocked_edges": [
|
||||
"sym://dotnet:dotnet.c#entry -> sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# dotnet-newtonsoft-deser-TBD
|
||||
Primary axis: lang-dotnet
|
||||
Tags: deserialization, json, polymorphic
|
||||
Languages: dotnet
|
||||
|
||||
## Variants
|
||||
- reachable: vulnerable function/path is on an executable route.
|
||||
- unreachable: same base image/config with control toggles that prune the path.
|
||||
|
||||
## Entrypoint & Controls (fill in)
|
||||
- entrypoints: e.g., http:/route, grpc method, tcp port, OCI hook
|
||||
- flags: e.g., feature_on=true, middleware_order=bad|good, module_loaded=true|false, LSM=enforcing|permissive
|
||||
|
||||
## Expected ground-truth path(s)
|
||||
See `images/*/reachgraph.truth.json`.
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/dotnet-newtonsoft-deser-TBD:reachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:Startup#Configure",
|
||||
"to": "sym://aspnet:UseEndpoints",
|
||||
"kind": "pipeline"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:dotnet.c#entry",
|
||||
"to": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/dotnet-newtonsoft-deser-TBD:reachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": true,
|
||||
"POLICY_MODE": "permissive"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://dotnet:dotnet.c#entry",
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/dotnet@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/dotnet.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://dotnet:dotnet.c#entry", "pid": 100}
|
||||
{"ts": 1.005, "event": "call", "sid": "sym://dotnet:dotnet.c#sink", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "TBD",
|
||||
"status": "affected",
|
||||
"justification": "reasoning_provided",
|
||||
"impact_statement": "Function-level path is reachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/dotnet-newtonsoft-deser-TBD:unreachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:Startup#Configure",
|
||||
"to": "sym://aspnet:UseEndpoints",
|
||||
"kind": "pipeline"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://dotnet:dotnet.c#entry",
|
||||
"to": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/dotnet-newtonsoft-deser-TBD:unreachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": false,
|
||||
"POLICY_MODE": "enforcing"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://dotnet:dotnet.c#entry",
|
||||
"sym://dotnet:dotnet.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/dotnet@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/dotnet.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://dotnet:dotnet.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://dotnet:dotnet.c#entry", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "TBD",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Pruned by configuration; path unreachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"id": "glibc-CVE-2023-4911-looney-tunables",
|
||||
"cve": "CVE-2023-4911",
|
||||
"description": "STUB: Replace with accurate description and threat model for the specific CVE/case.",
|
||||
"threat_model": {
|
||||
"entry_points": [
|
||||
"STUB: define concrete inputs"
|
||||
],
|
||||
"preconditions": [
|
||||
"STUB: feature flags / modules / protocols enabled"
|
||||
],
|
||||
"privilege_boundary": [
|
||||
"STUB: describe boundary (if any)"
|
||||
]
|
||||
},
|
||||
"ground_truth": {
|
||||
"reachable_variant": {
|
||||
"status": "affected",
|
||||
"evidence": {
|
||||
"symbols": [
|
||||
"sym://glibc:glibc.c#sink"
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://glibc:glibc.c#entry",
|
||||
"sym://glibc:glibc.c#sink"
|
||||
]
|
||||
],
|
||||
"runtime_proof": "traces.runtime.jsonl: lines 1-5"
|
||||
}
|
||||
},
|
||||
"unreachable_variant": {
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"evidence": {
|
||||
"pruning_reason": [
|
||||
"STUB: feature disabled, module absent, or policy denies"
|
||||
],
|
||||
"blocked_edges": [
|
||||
"sym://glibc:glibc.c#entry -> sym://glibc:glibc.c#sink"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# glibc-CVE-2023-4911-looney-tunables
|
||||
Primary axis: binary-hybrid
|
||||
Tags: env-vars, libc, ldso
|
||||
Languages: c
|
||||
|
||||
## Variants
|
||||
- reachable: vulnerable function/path is on an executable route.
|
||||
- unreachable: same base image/config with control toggles that prune the path.
|
||||
|
||||
## Entrypoint & Controls (fill in)
|
||||
- entrypoints: e.g., http:/route, grpc method, tcp port, OCI hook
|
||||
- flags: e.g., feature_on=true, middleware_order=bad|good, module_loaded=true|false, LSM=enforcing|permissive
|
||||
|
||||
## Expected ground-truth path(s)
|
||||
See `images/*/reachgraph.truth.json`.
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/glibc-CVE-2023-4911-looney-tunables:reachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://glibc:glibc.c#entry",
|
||||
"to": "sym://glibc:glibc.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/glibc-CVE-2023-4911-looney-tunables:reachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": true,
|
||||
"POLICY_MODE": "permissive"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://glibc:glibc.c#entry",
|
||||
"sym://glibc:glibc.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/glibc@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/glibc.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://glibc:glibc.c#entry", "pid": 100}
|
||||
{"ts": 1.005, "event": "call", "sid": "sym://glibc:glibc.c#sink", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2023-4911",
|
||||
"status": "affected",
|
||||
"justification": "reasoning_provided",
|
||||
"impact_statement": "Function-level path is reachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dsse_version": "1.0",
|
||||
"subject": [
|
||||
{
|
||||
"name": "ghcr.io/reachbench/glibc-CVE-2023-4911-looney-tunables:unreachable",
|
||||
"digest": {
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
}
|
||||
],
|
||||
"statement": {
|
||||
"type": "reachbench.attestation",
|
||||
"materials": [
|
||||
"sbom.cdx.json",
|
||||
"sbom.spdx.json",
|
||||
"symbols.json",
|
||||
"callgraph.static.json",
|
||||
"callgraph.framework.json",
|
||||
"reachgraph.truth.json",
|
||||
"vex.openvex.json"
|
||||
]
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "STUB",
|
||||
"sig": "STUB_SIGNATURE",
|
||||
"alg": "dilithium2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"edges": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"nodes": [
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#entry"
|
||||
},
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#sink"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "sym://glibc:glibc.c#entry",
|
||||
"to": "sym://glibc:glibc.c#sink",
|
||||
"kind": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"image": "ghcr.io/reachbench/glibc-CVE-2023-4911-looney-tunables:unreachable",
|
||||
"config_flags": {
|
||||
"FEATURE_FLAG": false,
|
||||
"POLICY_MODE": "enforcing"
|
||||
},
|
||||
"sha256": "STUB_DIGEST"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"sinks": [
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#sink",
|
||||
"kind": "generic"
|
||||
}
|
||||
],
|
||||
"paths": [
|
||||
[
|
||||
"sym://net:handler#read",
|
||||
"sym://glibc:glibc.c#entry",
|
||||
"sym://glibc:glibc.c#sink"
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"components": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-3.0",
|
||||
"creationInfo": {
|
||||
"created": "2025-11-07T22:40:04Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"components": [
|
||||
{
|
||||
"purl": "pkg:generic/glibc@0.0.1",
|
||||
"files": [
|
||||
{
|
||||
"path": "/src/glibc.c",
|
||||
"funcs": [
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#entry",
|
||||
"name": "entry",
|
||||
"range": {
|
||||
"start": 10,
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"sid": "sym://glibc:glibc.c#sink",
|
||||
"name": "sink",
|
||||
"range": {
|
||||
"start": 30,
|
||||
"end": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"ts": 1.001, "event": "call", "sid": "sym://glibc:glibc.c#entry", "pid": 100}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"author": "reachbench-2025",
|
||||
"timestamp": "2025-11-07T22:40:04Z",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2023-4911",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Pruned by configuration; path unreachable."
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user