Severity: Warning (data-leak in Servy.Service.log for affected users when EnableDebugLogs=true)
File / line: src/Servy.Service/Helpers/ServiceHelper.cs lines 23–42
Code:
private static readonly HashSet<string> SensitiveKeyWords = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
// --- System Integrity ---
"PASSWORD", "PWD", "SECRET", "KEY", "TOKEN", "AUTH", "CREDENTIAL", "CONNECTIONSTRING",
"CERTIFICATE", // For PFX/PEM paths or thumbprints
"API", // Catches API_URL_KEY or API_SECRET
"PRIVATE" // Catches PRIVATE_KEY or PRIVATE_TOKEN
};
...
private static readonly Regex MaskingRegex = new Regex(
@"(?i)(password|pwd|secret|key|token|auth|api|private)([:=\s]+)(?:""[^""]*""|[^\s""]+)",
RegexOptions.Compiled,
AppConfig.InputRegexTimeout);
What's wrong: Two parallel mask lists exist in the same file and they have drifted apart. They are used in different code paths but for the same purpose ("don't write sensitive material to disk"):
Keyword (in SensitiveKeyWords) |
In MaskingRegex ? |
Used by |
| PASSWORD |
✓ |
both |
| PWD |
✓ |
both |
| SECRET |
✓ |
both |
| KEY |
✓ |
both |
| TOKEN |
✓ |
both |
| AUTH |
✓ |
both |
| API |
✓ |
both |
| PRIVATE |
✓ |
both |
| CREDENTIAL |
✗ missing |
only env-var formatting |
| CONNECTIONSTRING |
✗ missing |
only env-var formatting |
| CERTIFICATE |
✗ missing |
only env-var formatting |
Net effect:
EnvironmentVariablesToString(...) (line 412–418, used for the environmentVariables block in LogStartupArguments) calls MaskSensitiveValue which hits the HashSet → variables named MY_CREDENTIAL, DB_CONNECTIONSTRING, SERVICE_CERTIFICATE are correctly masked.
MaskRawArguments(...) (line 442–457, used for realArgs, preLaunchExecutableArgs, failureProgramArgs, preStopExecutableArgs, postStopExecutableArgs, postLaunchExecutableArgs — i.e. every command-line argument string written to Servy.Service.log when EnableDebugLogs=true) only matches the regex → an argument like --credential MyDbPassw0rd or --connectionstring "Server=...;Pwd=..." or --certificate-thumbprint AB12CD34... is written to disk unmasked.
Concretely: a service started with
... --connectionstring "Server=tcp:db.foo.com,1433;User ID=admin;Password=Hunter2;" ...
will get the entire connection string (including Password=Hunter2) written to Servy.Service.log when EnableDebugLogs is on. The user who ticked "EnableDebugLogs" reasonably expected the same masking that applies to env vars.
Suggested fix: Single source of truth — derive the regex pattern from the HashSet so they cannot drift again:
private static readonly Regex MaskingRegex = new Regex(
@"(?i)\b(" + string.Join("|", SensitiveKeyWords.Select(Regex.Escape)) + @")\b([:=\s]+)(?:""[^""]*""|[^\s""]+)",
RegexOptions.Compiled,
AppConfig.InputRegexTimeout);
Notes:
Severity: Warning (data-leak in
Servy.Service.logfor affected users whenEnableDebugLogs=true)File / line:
src/Servy.Service/Helpers/ServiceHelper.cslines 23–42Code:
What's wrong: Two parallel mask lists exist in the same file and they have drifted apart. They are used in different code paths but for the same purpose ("don't write sensitive material to disk"):
SensitiveKeyWords)MaskingRegex?Net effect:
EnvironmentVariablesToString(...)(line 412–418, used for theenvironmentVariablesblock inLogStartupArguments) callsMaskSensitiveValuewhich hits the HashSet → variables namedMY_CREDENTIAL,DB_CONNECTIONSTRING,SERVICE_CERTIFICATEare correctly masked.MaskRawArguments(...)(line 442–457, used forrealArgs,preLaunchExecutableArgs,failureProgramArgs,preStopExecutableArgs,postStopExecutableArgs,postLaunchExecutableArgs— i.e. every command-line argument string written toServy.Service.logwhenEnableDebugLogs=true) only matches the regex → an argument like--credential MyDbPassw0rdor--connectionstring "Server=...;Pwd=..."or--certificate-thumbprint AB12CD34...is written to disk unmasked.Concretely: a service started with
will get the entire connection string (including
Password=Hunter2) written toServy.Service.logwhenEnableDebugLogsis on. The user who ticked "EnableDebugLogs" reasonably expected the same masking that applies to env vars.Suggested fix: Single source of truth — derive the regex pattern from the HashSet so they cannot drift again:
Notes:
\b...\bword-boundary fix here also addresses the over-masking direction noted in issue [Security] ServiceHelper.MaskingRegex — missing word boundary, partial substring matches mask non-secret keys #823 —KEYno longer matches insideMONKEY.Servy.psm1 Format-SecureLogMessage hardcodes the same listin PowerShell) — the real long-term fix is one canonical list of sensitive keywords shared by .NET and PowerShell, but the in-file unification above is a low-risk first step.