rules:
  - id: auth.py.flow.weak-password-hash
    languages:
      - python
    severity: ERROR
    message: |
      A password is being hashed with a fast, general-purpose digest from
      `hashlib` (MD5, SHA-1, SHA-256, SHA-512). These algorithms are designed
      to be fast, which makes offline brute-force and rainbow-table attacks
      cheap. They are NOT suitable for storing passwords.

      Use a dedicated, slow password-hashing function with a per-password salt
      and a tunable work factor: `bcrypt` (`bcrypt.hashpw`), `argon2`
      (`argon2.PasswordHasher().hash`), `scrypt`, or a wrapper such as
      `passlib`. These resist brute-force by design.
    # Scoped to hashlib digests whose input is named like a password
    # (metavariable-regex on the argument). `password.encode()` is handled
    # because the base name `password` still matches. Checksums, file digests
    # (`hashlib.sha256(file_bytes)`), `hmac.new(...)`, and real password
    # hashers (bcrypt/argon2/passlib) are NOT matched.
    pattern-either:
      - patterns:
          - pattern-either:
              - pattern: hashlib.md5($PW)
              - pattern: hashlib.sha1($PW)
              - pattern: hashlib.sha256($PW)
              - pattern: hashlib.sha512($PW)
          - metavariable-regex:
              metavariable: $PW
              regex: (?i)^.*(password|passwd|pwd).*$
      - patterns:
          - pattern-either:
              - pattern: |
                  $H = hashlib.md5(...)
                  ...
                  $H.update($PW)
              - pattern: |
                  $H = hashlib.sha1(...)
                  ...
                  $H.update($PW)
              - pattern: |
                  $H = hashlib.sha256(...)
                  ...
                  $H.update($PW)
              - pattern: |
                  $H = hashlib.sha512(...)
                  ...
                  $H.update($PW)
          - metavariable-regex:
              metavariable: $PW
              regex: (?i)^.*(password|passwd|pwd).*$
    metadata:
      oauthlint-rule-id: AUTH-PY-FLOW-001
      oauthlint-doc-url: https://oauthlint.dev/rules/py-flow-weak-password-hash
      category: security
      cwe: CWE-916
      owasp: A02:2021
      llm-prevalence: HIGH
      technology:
        - hashlib
      references:
        - https://cwe.mitre.org/data/definitions/916.html
        - https://argon2-cffi.readthedocs.io/en/stable/
        - https://passlib.readthedocs.io/en/stable/
