fix(hide-secrets): accept punctuation in a credential value

The value filter only allowed the URL-safe Base64 alphabet, so a password
such as hunter2!brahms or p@ssw0rd!2026 passed through unredacted while
the upstream keyword plugin had already matched it. The filter now rejects
only whitespace and brackets, which keeps function calls, subscripts and
sentences out while letting symbol-heavy passwords through.
This commit is contained in:
Yucheng He 2026-09-08 10:38:07 -07:00
parent 014f20be5f
commit 7b580ce0d9
2 changed files with 24 additions and 3 deletions

View file

@ -4,7 +4,7 @@ from typing import Final
from detect_secrets.plugins.keyword import KeywordDetector
_CREDENTIAL_VALUE: Final = re.compile(r"[A-Za-z0-9_.~+/-]+={0,2}")
_CREDENTIAL_VALUE: Final = re.compile(r"[^\s()\[\]]+")
_ENVIRONMENT_REFERENCE: Final = re.compile(r"os\.environ/\w+", re.IGNORECASE)
_ENVIRONMENT_VARIABLE_NAME: Final = re.compile(r"[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+")
_LOWERCASE_WORD_SEQUENCE: Final = re.compile(r"[a-z]+(?:[-._/][a-z]+)+")

View file

@ -90,6 +90,12 @@ def test_scan_message_preserves_quoted_benign_identifiers():
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
),
("password=aB3dE6gH9jK2", "aB3dE6gH9jK2"),
("api_key: hunter2!brahms", "hunter2!brahms"),
('db_password: "p@ssw0rd!2026"', "p@ssw0rd!2026"),
(
'url: "postgresql://user:s3cr3t@db-host:5432/app"',
"postgresql://user:s3cr3t@db-host:5432/app",
),
],
ids=[
"env-password",
@ -108,6 +114,9 @@ def test_scan_message_preserves_quoted_benign_identifiers():
"django-secret-key",
"slashed-aws-secret",
"shortest-accepted-value",
"punctuation-bearing-password",
"symbol-heavy-password",
"connection-string-under-a-credential-key",
],
)
def test_scan_message_redacts_credentials_assigned_to_credential_keys(content, secret):
@ -139,11 +148,11 @@ def test_scan_message_redacts_credentials_assigned_to_credential_keys(content, s
"langfuse_secret: os.environ/LANGFUSE_PROJECT1_SECRET",
"api_key = OPENAI_API_KEY",
"password = pwd12345678",
"api_key: hunter2!brahms",
"model_key: gpt-4o-mini-2024-07-18",
"openrouter/anthropic/claude-3-5-sonnet-20240620",
'{"content-type": "application/json"}',
"passwordless_login: enabled-for-all-users",
'password: "I forgot mine, can you reset it"',
"secret_sauce: tomatoes-basil-garlic-oregano",
"user_secret_question: what-was-your-first-pet",
"password_reset_url: example.com/reset-password/flow",
@ -153,6 +162,12 @@ def test_scan_message_redacts_credentials_assigned_to_credential_keys(content, s
'api_key = "OPENAI_API_KEY"',
"model_list:\n - litellm_params:\n api_key: 'PERPLEXITY_API_KEY'",
'config = build(_provider("ve_missing", api_key_env="VE_MISSING_KEY"))',
"api_key = get_api_key_from_env()",
"api_key = get_secret_str(MISTRAL_OCR_API_KEY_ENV_VAR)",
"secret_manager = MagicMock(spec=BaseSecretManager)",
"api_key = self.resolve_server_api_key(",
"api_key = sys.argv[1]",
"password = credentials[environment]",
],
ids=[
"prose-password",
@ -175,11 +190,11 @@ def test_scan_message_redacts_credentials_assigned_to_credential_keys(content, s
"env-reference-nested",
"env-variable-name",
"below-minimum-length",
"non-credential-charset",
"model-name",
"namespaced-model-name",
"media-type",
"hyphenated-english",
"quoted-sentence-under-a-credential-key",
"hyphenated-phrase",
"hyphenated-question",
"url-under-credential-key",
@ -189,6 +204,12 @@ def test_scan_message_redacts_credentials_assigned_to_credential_keys(content, s
"quoted-env-variable-name",
"quoted-env-name-in-a-config",
"quoted-env-name-in-a-code-paste",
"bare-call",
"call-with-an-argument",
"keyword-argument-call",
"unclosed-call",
"positional-subscript",
"keyed-subscript",
],
)
def test_scan_message_keeps_benign_values(content):