diff --git a/src/websec_validator/extractors/crypto_usage.py b/src/websec_validator/extractors/crypto_usage.py index e6a93ba..8e8913f 100644 --- a/src/websec_validator/extractors/crypto_usage.py +++ b/src/websec_validator/extractors/crypto_usage.py @@ -100,7 +100,12 @@ def _unparenthesized(value: str) -> str: # Identifier-shaped arguments: not credentials, so hashing them weakly is not a password-hash bug. -_NON_CREDENTIAL_ARGUMENT = re.compile(r"(?:^|\.)(?:id|email|userId|user_id|tenantId|tenant_id)$", re.I) +_NON_CREDENTIAL_ARGUMENT = re.compile( + r"(?:^|\.)(?:id|email|userId|user_id|tenantId|tenant_id)$|" + r"(?:^|\.)(?:username|org_id|organizationId|session_id|sessionId|token|nonce|ts|timestamp)$|" + r"crypto\.randomBytes|randomBytes|uuid|uuidv4|crypto\.randomUUID|Date\.now", + re.I +) def _credential_operand(value: str) -> bool: diff --git a/tests/test_pentest_regressions.py b/tests/test_pentest_regressions.py index c88fc85..2156fbe 100644 --- a/tests/test_pentest_regressions.py +++ b/tests/test_pentest_regressions.py @@ -571,6 +571,17 @@ def test_client_findings_carry_their_own_file(self): ctv = [f for f in out["findings"] if f["attack_class"] == "client-tamper-vector"][0] self.assertEqual(ctv["file"], "app/Pay.tsx") + def test_crypto_usage_skips_benign_non_credential_args_in_pw_context(self): + # regression: random tokens, session ids, and org ids created inside password functions are not password hashes + from websec_validator.extractors.crypto_usage import CryptoUsageExtractor + out = CryptoUsageExtractor().extract(repo({ + "t1.js": "function verifyPassword() { return createHash('sha256').update(req.body.username).digest('hex'); }", + "t2.ts": "const hashPassword = () => { const o = createHash('sha256').update(this.organizationId).digest(); }", + "t3.py": "def set_password(): session_id = hashlib.sha256(os.urandom(32)).hexdigest()", + "t4.js": "function comparePassword() { let t = createHash('sha256').update(crypto.randomBytes(32)).digest(); }" + }), {}) + self.assertEqual([f for f in out["findings"] if f["kind"] == "weak-password-hash"], []) + class AuthSchemeTests(unittest.TestCase): """P2: HMAC-signed cookies must not misread as api-key (which staged JWT probes for a no-JWT app)."""