rules:
  - id: auth.py.flow.oauth-credential-in-log
    languages:
      - python
    severity: ERROR
    message: |
      An OAuth/OIDC credential from the request flows into a logging call.
      The tainted value is an authorization `code`, an `access_token` /
      `refresh_token` / `id_token`, a bearer `token`, a `client_secret`, or
      the raw `Authorization` header, and the sink is `print`, `logging.*`,
      or a `logger.*` call. Logs are written to files, shipped to aggregators
      (Datadog, Splunk, CloudWatch) and read by people and systems that should
      never see live credentials. A leaked authorization code or token can be
      replayed to impersonate the user or complete the OAuth exchange
      (CWE-532).

      Never log the raw credential. Redact or mask it before logging, log a
      non-sensitive identifier instead (a user id, a key id), or drop the field
      entirely.
    # Taint mode so indirection is caught: `at = request.args.get("access_token");
    # logger.info(at)` flags, not just the inline form. The source list is
    # narrowed to OAuth/OIDC credential field names (and the Authorization
    # header) via a metavariable-regex on the accessor key, so logging a benign
    # field such as `request.args.get("page")` does not fire. Routing the value
    # through a redaction/masking helper clears the taint.
    mode: taint
    pattern-sources:
      # Credential-named request fields: request.args.get("code"),
      # request.form["access_token"], flask.request.json.get("id_token"), …
      - patterns:
          - pattern-either:
              - pattern: request.args.get($K)
              - pattern: request.form.get($K)
              - pattern: request.values.get($K)
              - pattern: request.json.get($K)
              - pattern: request.args[$K]
              - pattern: request.form[$K]
              - pattern: request.values[$K]
              - pattern: request.json[$K]
              - pattern: flask.request.args.get($K)
              - pattern: flask.request.form.get($K)
              - pattern: flask.request.json.get($K)
          - metavariable-regex:
              metavariable: $K
              regex: (?i)^["'](?:code|access[_-]?token|accesstoken|refresh[_-]?token|refreshtoken|id[_-]?token|idtoken|token|client[_-]?secret|clientsecret)["']$
      # Raw Authorization header.
      - patterns:
          - pattern-either:
              - pattern: request.headers.get($K)
              - pattern: request.headers[$K]
              - pattern: flask.request.headers.get($K)
          - metavariable-regex:
              metavariable: $K
              regex: (?i)^["']authorization["']$
    pattern-sanitizers:
      # Redaction / masking helpers: the value that reaches the log is no
      # longer the live credential.
      - pattern: redact(...)
      - pattern: mask(...)
      - pattern: mask_token(...)
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: print(...)
              - pattern: logging.info(...)
              - pattern: logging.debug(...)
              - pattern: logging.warning(...)
              - pattern: logging.error(...)
              - pattern: logging.exception(...)
              - pattern: logging.critical(...)
              # logger.<level>(...), a log-named receiver with a log-level method.
              - patterns:
                  - pattern: $LOG.$LEVEL(...)
                  - metavariable-regex:
                      metavariable: $LOG
                      regex: (?i)^.*log(?:ger)?$
                  - metavariable-regex:
                      metavariable: $LEVEL
                      regex: ^(?:info|debug|warning|warn|error|exception|critical)$
    metadata:
      oauthlint-rule-id: AUTH-PY-FLOW-009
      oauthlint-doc-url: https://oauthlint.dev/rules/py-flow-oauth-credential-in-log
      category: security
      cwe: CWE-532
      owasp: API8:2023
      llm-prevalence: MEDIUM
      technology:
        - flask
      references:
        - https://cwe.mitre.org/data/definitions/532.html
        - https://datatracker.ietf.org/doc/html/rfc6749#section-10.3
        - https://owasp.org/API-Security/editions/2023/en/0xa8-security-misconfiguration/
