fix(security): enforce audited account, network and resource boundaries

Implement B01-B06 with regression coverage and retained validation evidence. Preserve the production ingress preflight; F04 runtime verification remains open.
This commit is contained in:
cesnimda
2026-09-09 18:21:47 +02:00
parent 7d641edc7b
commit 0954876295
116 changed files with 10101 additions and 122 deletions
@@ -170,7 +170,7 @@ public sealed class JobImportService
if (IPAddress.TryParse(uri.Host, out var ip))
{
if (IsBlockedAddress(ip))
if (JobImportHttpTransport.IsBlockedAddress(ip))
{
return UrlValidationResult.Reject("Local or private network URLs are not allowed.");
}
@@ -188,7 +188,7 @@ public sealed class JobImportService
return UrlValidationResult.Reject("Host resolution failed.");
}
if (addresses.Length == 0 || addresses.Any(IsBlockedAddress))
if (addresses.Length == 0 || addresses.Any(JobImportHttpTransport.IsBlockedAddress))
{
return UrlValidationResult.Reject("Local or private network URLs are not allowed.");
}
@@ -196,35 +196,6 @@ public sealed class JobImportService
return UrlValidationResult.Allow(uri.ToString());
}
private static bool IsBlockedAddress(IPAddress ip)
{
if (IPAddress.IsLoopback(ip)) return true;
if (ip.Equals(IPAddress.Any) || ip.Equals(IPAddress.IPv6Any)) return true;
if (ip.Equals(IPAddress.None) || ip.Equals(IPAddress.IPv6None)) return true;
if (ip.IsIPv6LinkLocal || ip.IsIPv6SiteLocal || ip.IsIPv6Multicast || ip.IsIPv6Teredo) return true;
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
var b = ip.GetAddressBytes();
return b[0] == 10 ||
b[0] == 0 ||
b[0] == 127 ||
(b[0] == 100 && b[1] >= 64 && b[1] <= 127) ||
(b[0] == 169 && b[1] == 254) ||
(b[0] == 172 && b[1] >= 16 && b[1] <= 31) ||
(b[0] == 192 && b[1] == 168) ||
(b[0] == 198 && (b[1] == 18 || b[1] == 19));
}
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
var bytes = ip.GetAddressBytes();
return (bytes[0] & 0xfe) == 0xfc; // fc00::/7 unique local addresses
}
return false;
}
private sealed record UrlValidationResult(bool Allowed, string Normalized, string Error)
{
public static UrlValidationResult Allow(string normalized) => new(true, normalized, string.Empty);