feat: add security sink detection patterns for JavaScript/TypeScript

- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations).
- Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns.
- Added `package-lock.json` for dependency management.
This commit is contained in:
StellaOps Bot
2025-12-22 23:21:21 +02:00
parent 3ba7157b00
commit 5146204f1b
529 changed files with 73579 additions and 5985 deletions

View File

@@ -44,7 +44,7 @@ public sealed record RuntimeStaticMergeResult
/// <summary>
/// Merged graph with runtime annotations.
/// </summary>
public required CallGraph MergedGraph { get; init; }
public required RichGraph MergedGraph { get; init; }
/// <summary>
/// Statistics about the merge operation.
@@ -141,7 +141,7 @@ public sealed class RuntimeStaticMerger
/// Merge runtime events into a static call graph.
/// </summary>
public RuntimeStaticMergeResult Merge(
CallGraph staticGraph,
RichGraph staticGraph,
IEnumerable<RuntimeCallEvent> runtimeEvents)
{
ArgumentNullException.ThrowIfNull(staticGraph);
@@ -158,7 +158,7 @@ public sealed class RuntimeStaticMerger
var observedEdges = new List<ObservedEdge>();
var runtimeOnlyEdges = new List<RuntimeOnlyEdge>();
var modifiedEdges = new List<CallEdge>();
var modifiedEdges = new List<RichGraphEdge>();
var matchedEdgeKeys = new HashSet<string>(StringComparer.Ordinal);
foreach (var (edgeKey, aggregate) in runtimeEdgeAggregates)
@@ -177,21 +177,12 @@ public sealed class RuntimeStaticMerger
if (staticEdgeIndex.TryGetValue(edgeKey, out var staticEdge))
{
// Edge exists in static graph - mark as observed
// Edge exists in static graph - mark as observed with boosted confidence
matchedEdgeKeys.Add(edgeKey);
var observedMetadata = new ObservedEdgeMetadata
{
FirstObserved = aggregate.FirstObserved,
LastObserved = aggregate.LastObserved,
ObservationCount = aggregate.ObservationCount,
TraceDigest = aggregate.TraceDigest
};
var boostedEdge = staticEdge with
{
Confidence = _options.ObservedConfidenceBoost,
Observed = observedMetadata
Confidence = _options.ObservedConfidenceBoost
};
modifiedEdges.Add(boostedEdge);
@@ -207,22 +198,16 @@ public sealed class RuntimeStaticMerger
}
else if (_options.AddRuntimeOnlyEdges)
{
// Edge only exists in runtime - add it
var runtimeEdge = new CallEdge
{
From = aggregate.From,
To = aggregate.To,
Kind = CallEdgeKind.Dynamic,
Confidence = ComputeRuntimeOnlyConfidence(aggregate),
Evidence = "runtime_observation",
Observed = new ObservedEdgeMetadata
{
FirstObserved = aggregate.FirstObserved,
LastObserved = aggregate.LastObserved,
ObservationCount = aggregate.ObservationCount,
TraceDigest = aggregate.TraceDigest
}
};
// Edge only exists in runtime - add it as dynamic edge
var runtimeEdge = new RichGraphEdge(
From: aggregate.From,
To: aggregate.To,
Kind: "dynamic",
Purl: null,
SymbolDigest: null,
Evidence: new[] { "runtime_observation" },
Confidence: ComputeRuntimeOnlyConfidence(aggregate),
Candidates: null);
modifiedEdges.Add(runtimeEdge);
runtimeOnlyEdges.Add(new RuntimeOnlyEdge
@@ -239,7 +224,7 @@ public sealed class RuntimeStaticMerger
}
// Build merged edge list: unmatched static + modified
var mergedEdges = new List<CallEdge>();
var mergedEdges = new List<RichGraphEdge>();
foreach (var edge in staticGraph.Edges)
{
var key = BuildEdgeKey(edge.From, edge.To);
@@ -252,16 +237,16 @@ public sealed class RuntimeStaticMerger
var mergedGraph = staticGraph with
{
Edges = mergedEdges.ToImmutableArray()
Edges = mergedEdges
};
var statistics = new MergeStatistics
{
StaticEdgeCount = staticGraph.Edges.Length,
StaticEdgeCount = staticGraph.Edges.Count,
RuntimeEventCount = runtimeEdgeAggregates.Count,
MatchedEdgeCount = matchedEdgeKeys.Count,
RuntimeOnlyEdgeCount = runtimeOnlyEdges.Count,
UnmatchedStaticEdgeCount = staticGraph.Edges.Length - matchedEdgeKeys.Count
UnmatchedStaticEdgeCount = staticGraph.Edges.Count - matchedEdgeKeys.Count
};
_logger.LogInformation(
@@ -280,9 +265,9 @@ public sealed class RuntimeStaticMerger
};
}
private static Dictionary<string, CallEdge> BuildStaticEdgeIndex(CallGraph graph)
private static Dictionary<string, RichGraphEdge> BuildStaticEdgeIndex(RichGraph graph)
{
var index = new Dictionary<string, CallEdge>(StringComparer.Ordinal);
var index = new Dictionary<string, RichGraphEdge>(StringComparer.Ordinal);
foreach (var edge in graph.Edges)
{
var key = BuildEdgeKey(edge.From, edge.To);

View File

@@ -1,25 +1 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Npgsql" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Scanner.Core\StellaOps.Scanner.Core.csproj" />
<ProjectReference Include="..\StellaOps.Scanner.Cache\StellaOps.Scanner.Cache.csproj" />
<ProjectReference Include="..\StellaOps.Scanner.ProofSpine\StellaOps.Scanner.ProofSpine.csproj" />
<ProjectReference Include="..\StellaOps.Scanner.Surface.Env\StellaOps.Scanner.Surface.Env.csproj" />
<ProjectReference Include="..\StellaOps.Scanner.SmartDiff\StellaOps.Scanner.SmartDiff.csproj" />
<ProjectReference Include="..\..\StellaOps.Scanner.Analyzers.Native\StellaOps.Scanner.Analyzers.Native.csproj" />
<ProjectReference Include="..\..\..\Attestor\StellaOps.Attestor\StellaOps.Attestor.Core\StellaOps.Attestor.Core.csproj" />
<ProjectReference Include="..\..\..\Attestor\StellaOps.Attestor.Envelope\StellaOps.Attestor.Envelope.csproj" />
<ProjectReference Include="..\..\..\Attestor\__Libraries\StellaOps.Attestor.ProofChain\StellaOps.Attestor.ProofChain.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Replay.Core\StellaOps.Replay.Core.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj" />
</ItemGroup>
</Project>