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

@@ -3,7 +3,6 @@ using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using StellaOps.Scanner.Reachability.Slices;
namespace StellaOps.Scanner.Storage.Oci;
@@ -39,7 +38,11 @@ public sealed record SlicePullOptions
public sealed record SlicePullResult
{
public required bool Success { get; init; }
public ReachabilitySlice? Slice { get; init; }
/// <summary>
/// Raw slice data as JSON element (decoupled from ReachabilitySlice type).
/// Consumer should deserialize to appropriate type.
/// </summary>
public JsonElement? SliceData { get; init; }
public string? SliceDigest { get; init; }
public byte[]? DsseEnvelope { get; init; }
public string? Error { get; init; }
@@ -96,7 +99,7 @@ public sealed class SlicePullService : IDisposable
return new SlicePullResult
{
Success = true,
Slice = cached!.Slice,
SliceData = cached!.SliceData,
SliceDigest = digest,
DsseEnvelope = cached.DsseEnvelope,
FromCache = true,
@@ -185,9 +188,14 @@ public sealed class SlicePullService : IDisposable
};
}
// Parse slice
var slice = JsonSerializer.Deserialize<ReachabilitySlice>(sliceBytes, JsonOptions);
if (slice == null)
// Parse slice as raw JSON element (decoupled from ReachabilitySlice type)
JsonElement sliceData;
try
{
using var doc = JsonDocument.Parse(sliceBytes);
sliceData = doc.RootElement.Clone();
}
catch (JsonException)
{
return new SlicePullResult
{
@@ -216,7 +224,7 @@ public sealed class SlicePullService : IDisposable
{
AddToCache(cacheKey, new CachedSlice
{
Slice = slice,
SliceData = sliceData,
DsseEnvelope = dsseEnvelope,
SignatureVerified = signatureVerified,
ExpiresAt = DateTimeOffset.UtcNow.Add(_options.CacheTtl)
@@ -230,7 +238,7 @@ public sealed class SlicePullService : IDisposable
return new SlicePullResult
{
Success = true,
Slice = slice,
SliceData = sliceData,
SliceDigest = digest,
DsseEnvelope = dsseEnvelope,
FromCache = false,
@@ -346,7 +354,7 @@ public sealed class SlicePullService : IDisposable
var index = await response.Content.ReadFromJsonAsync<OciReferrersIndex>(JsonOptions, cancellationToken)
.ConfigureAwait(false);
return index?.Manifests ?? Array.Empty<OciReferrer>();
return (IReadOnlyList<OciReferrer>?)index?.Manifests ?? Array.Empty<OciReferrer>();
}
catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException)
{
@@ -430,7 +438,7 @@ public sealed class SlicePullService : IDisposable
private sealed record CachedSlice
{
public required ReachabilitySlice Slice { get; init; }
public required JsonElement SliceData { get; init; }
public byte[]? DsseEnvelope { get; init; }
public bool SignatureVerified { get; init; }
public required DateTimeOffset ExpiresAt { get; init; }