Skip to content

[Security] Servy.Service ServiceHelper — SensitiveKeyWords list and MaskingRegex pattern are out of sync (CREDENTIAL / CONNECTIONSTRING / CERTIFICATE missing from regex) #896

@Christophe-Rogiers

Description

@Christophe-Rogiers

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:

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions