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:
130
src/Excititor/StellaOps.Excititor.WebService/Program.Helpers.cs
Normal file
130
src/Excititor/StellaOps.Excititor.WebService/Program.Helpers.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Excititor.Core.Aoc;
|
||||
using StellaOps.Excititor.Storage.Mongo;
|
||||
public partial class Program
|
||||
{
|
||||
private const string TenantHeaderName = "X-Stella-Tenant";
|
||||
|
||||
private static bool TryResolveTenant(HttpContext context, VexMongoStorageOptions options, bool requireHeader, out string tenant, out IResult? problem)
|
||||
{
|
||||
tenant = options.DefaultTenant;
|
||||
problem = null;
|
||||
|
||||
if (context.Request.Headers.TryGetValue(TenantHeaderName, out var headerValues) && headerValues.Count > 0)
|
||||
{
|
||||
var requestedTenant = headerValues[0]?.Trim();
|
||||
if (string.IsNullOrEmpty(requestedTenant))
|
||||
{
|
||||
problem = Results.Problem(detail: "X-Stella-Tenant header must not be empty.", statusCode: StatusCodes.Status400BadRequest, title: "Validation error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(requestedTenant, options.DefaultTenant, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var detail = string.Format(CultureInfo.InvariantCulture, "Tenant '{0}' is not allowed for this Excititor deployment.", requestedTenant);
|
||||
problem = Results.Problem(detail: detail, statusCode: StatusCodes.Status403Forbidden, title: "Forbidden");
|
||||
return false;
|
||||
}
|
||||
|
||||
tenant = requestedTenant;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (requireHeader)
|
||||
{
|
||||
var detail = string.Format(CultureInfo.InvariantCulture, "{0} header is required.", TenantHeaderName);
|
||||
problem = Results.Problem(detail: detail, statusCode: StatusCodes.Status400BadRequest, title: "Validation error");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, string> ReadMetadata(BsonValue value)
|
||||
{
|
||||
if (value is not BsonDocument doc || doc.ElementCount == 0)
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
var result = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var element in doc.Elements)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(element.Name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result[element.Name] = element.Value?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool TryDecodeCursor(string? cursor, out DateTimeOffset timestamp, out string digest)
|
||||
{
|
||||
timestamp = default;
|
||||
digest = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(cursor))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var payload = Encoding.UTF8.GetString(Convert.FromBase64String(cursor));
|
||||
var parts = payload.Split('|');
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DateTimeOffset.TryParse(parts[0], CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out timestamp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
digest = parts[1];
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string EncodeCursor(DateTime timestamp, string digest)
|
||||
{
|
||||
var payload = string.Format(CultureInfo.InvariantCulture, "{0:O}|{1}", timestamp, digest);
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(payload));
|
||||
}
|
||||
|
||||
private static IResult ValidationProblem(string message)
|
||||
=> Results.Problem(detail: message, statusCode: StatusCodes.Status400BadRequest, title: "Validation error");
|
||||
|
||||
private static IResult MapGuardException(ExcititorAocGuardException exception)
|
||||
{
|
||||
var violations = exception.Violations.Select(violation => new
|
||||
{
|
||||
code = violation.ErrorCode,
|
||||
path = violation.Path,
|
||||
message = violation.Message
|
||||
});
|
||||
|
||||
return Results.Problem(
|
||||
detail: "VEX document failed Aggregation-Only Contract validation.",
|
||||
statusCode: StatusCodes.Status400BadRequest,
|
||||
title: "AOC violation",
|
||||
extensions: new Dictionary<string, object?>
|
||||
{
|
||||
["violations"] = violations.ToArray(),
|
||||
["primaryCode"] = exception.PrimaryErrorCode,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user