rules:
  - id: auth.py.flow.requests-verify-disabled
    languages:
      - python
    severity: ERROR
    message: |
      A `requests` call disables TLS certificate verification with
      `verify=False`. This silences the validation of the server's
      certificate, so an attacker who can intercept the connection can
      present any certificate and read or tamper with the traffic, a
      classic man-in-the-middle exposure. For OAuth/OIDC this leaks
      authorization codes, access tokens and client secrets.

      Never set `verify=False`. Leave verification on (the default) so the
      system CA bundle is used. In development against a private CA, point
      `verify` at the CA bundle instead, e.g.
      `requests.get(url, verify="/path/to/ca-bundle.pem")` or set the
      `REQUESTS_CA_BUNDLE` env var (certifi).
    # Scoped to `requests.<method>(...)`, `requests.request(...)` and Session
    # objects (`$SESSION.<method>(...)`). Fires only on the literal
    # `verify=False`; `verify=True` and `verify="/path/ca.pem"` are not flagged.
    patterns:
      - pattern-either:
          - pattern: requests.get(..., verify=$V, ...)
          - pattern: requests.post(..., verify=$V, ...)
          - pattern: requests.put(..., verify=$V, ...)
          - pattern: requests.delete(..., verify=$V, ...)
          - pattern: requests.patch(..., verify=$V, ...)
          - pattern: requests.head(..., verify=$V, ...)
          - pattern: requests.options(..., verify=$V, ...)
          - pattern: requests.request(..., verify=$V, ...)
          - pattern: $SESSION.get(..., verify=$V, ...)
          - pattern: $SESSION.post(..., verify=$V, ...)
          - pattern: $SESSION.put(..., verify=$V, ...)
          - pattern: $SESSION.delete(..., verify=$V, ...)
          - pattern: $SESSION.patch(..., verify=$V, ...)
          - pattern: $SESSION.head(..., verify=$V, ...)
          - pattern: $SESSION.options(..., verify=$V, ...)
          - pattern: $SESSION.request(..., verify=$V, ...)
      # Fire only on the literal `False` (unchanged detection), and focus the
      # match/fix on that value token so the autofix flips just it, leaving the
      # rest of the call intact.
      - metavariable-regex:
          metavariable: $V
          regex: ^False$
      - focus-metavariable: $V
    # Safe, deterministic autofix: `True` is the library default (verification
    # on) and the exact value the rule treats as compliant, so it fully resolves
    # the finding. Only the value token is rewritten (`verify=False` -> `verify=True`).
    fix: "True"
    metadata:
      oauthlint-rule-id: AUTH-PY-FLOW-002
      oauthlint-doc-url: https://oauthlint.dev/rules/py-flow-requests-verify-disabled
      category: security
      cwe: CWE-295
      owasp: A02:2021
      llm-prevalence: HIGH
      technology:
        - requests
      references:
        - https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification
        - https://cwe.mitre.org/data/definitions/295.html
