Files
SecretSecurity/SecretSecurity/Validator.cs
T
2026-06-17 16:44:04 +01:00

173 lines
5.6 KiB
C#

using SecretSecurity.Models;
using System.Text.RegularExpressions;
namespace SecretSecurity
{
public static class Validator
{
// 1. Explicit secret assignments (HIGH confidence)
static Regex _explicitSecret = new Regex(
@"(?i)(api[_-]?key|secret|token|access[_-]?key|auth[_-]?token)\s*[:=]\s*[\""']?(?<value>[a-z0-9_\-]{16,})[\""']?",
RegexOptions.Compiled);
// 2. Provider-specific tokens (VERY high confidence)
static Regex _providerSecrets = new Regex(
@"(AKIA[0-9A-Z]{16}|sk_live_[0-9a-zA-Z]{24,}|ghp_[0-9a-zA-Z]{36}|xox[baprs]-[0-9a-zA-Z-]{10,})",
RegexOptions.Compiled);
// 3. Private key blocks
static Regex _privateKey = new Regex(
@"-----BEGIN (RSA|EC|OPENSSH) PRIVATE KEY-----",
RegexOptions.Compiled);
// 4. High entropy fallback (LIMITED usage only)
static Regex _randomBlob = new Regex(
@"\b[a-zA-Z0-9_\-]{40,}\b",
RegexOptions.Compiled);
// 5. General Connection Strings
static Regex _generalConnString = new Regex(
"(?i)\\b(server|data source|database|uid|user id|pwd|password)\\s*=\\s*[^;]+",
RegexOptions.Compiled);
// 6. Postgres Connection Strings
static Regex _postgres = new Regex(
"(?i)(postgres|mysql|mongodb|redis):\\/\\/[^\\\\s\\\"']+",
RegexOptions.Compiled);
// 7. Azure Connection Strings
static Regex _azureConnString = new Regex(
"(?i)(DefaultEndpointsProtocol|AccountName|AccountKey)=",
RegexOptions.Compiled);
public static SecretFinding? FindSecret(string line)
{
if (string.IsNullOrWhiteSpace(line))
return null;
// 1. Provider secrets (highest confidence)
if (_providerSecrets.IsMatch(line))
{
return new SecretFinding
{
Type = FindingType.Token,
Severity = Severity.Critical,
ValuePreview = Mask(line)
};
}
// 2. Private keys
if (_privateKey.IsMatch(line))
{
return new SecretFinding
{
Type = FindingType.ApiKey,
Severity = Severity.Critical,
ValuePreview = "-----BEGIN **** KEY-----"
};
}
// 3. Explicit assignment secrets
var explicitMatch = _explicitSecret.Match(line);
if (explicitMatch.Success)
{
return new SecretFinding
{
Type = FindingType.ApiKey | FindingType.Token,
Severity = Severity.High,
ValuePreview = Mask(explicitMatch.Value)
};
}
// 4. Connection strings (general)
if (_generalConnString.IsMatch(line))
{
if (IsSafeDevConnection(line))
{
return null;
}
return new SecretFinding
{
Type = FindingType.ConnectionString,
Severity = Severity.High,
ValuePreview = MaskConnection(line)
};
}
// 5. Postgres / DB URLs
if (_postgres.IsMatch(line))
{
return new SecretFinding
{
Type = FindingType.ConnectionString,
Severity = Severity.High,
ValuePreview = Mask(line)
};
}
// 6. Azure connection strings
if (_azureConnString.IsMatch(line))
{
return new SecretFinding
{
Type = FindingType.ConnectionString,
Severity = Severity.Critical,
ValuePreview = Mask(line)
};
}
// 7. Fallback entropy check (low confidence)
if (_randomBlob.IsMatch(line) && LooksSuspicious(line))
{
return new SecretFinding
{
Type = FindingType.SuspiciousBlob,
Severity = Severity.Warning,
ValuePreview = Mask(line)
};
}
return null;
}
static string Mask(string value)
{
if (string.IsNullOrEmpty(value))
return value;
if (value.Length <= 10)
return "****";
return value.Substring(0, 4) + "****" + value[^2..];
}
static string MaskConnection(string conn)
{
return Regex.Replace(conn,
"(?i)(password|pwd|user id|uid|key)=([^;]+)",
"$1=****");
}
static bool LooksSuspicious(string line)
{
// reduce false positives
return line.Contains("=") ||
line.Contains(":") ||
line.Contains("token") ||
line.Contains("key") ||
line.Contains("secret");
}
static bool IsSafeDevConnection(string line)
{
line = line.ToLowerInvariant();
return line.Contains("localhost") ||
line.Contains("127.0.0.1") ||
line.Contains("::1") ||
line.Contains("database=mydb") && line.Contains("trusted_connection=true") ||
line.Contains("integrated security=true");
}
}
}