rules:
  - id: auth.py.oauth.hardcoded-client-secret
    languages:
      - python
    severity: ERROR
    message: |
      An OAuth client secret is passed as a string literal to the OAuth client.
      Committed to source control it is one search away from compromise, letting
      an attacker impersonate your application at the authorization server and
      exchange codes for tokens (CWE-798). AI-generated OAuth snippets inline the
      secret to make the example run.

      Read it from the environment or a secret store instead, e.g.
      `client_secret=os.environ["OAUTH_CLIENT_SECRET"]`.
    pattern-either:
      - pattern: OAuth2Session($ID, "...", ...)
      - pattern: authlib.integrations.requests_client.OAuth2Session($ID, "...", ...)
      - pattern: OAuth2Session(..., client_secret="...", ...)
      - pattern: WebApplicationClient(..., client_secret="...", ...)
      - pattern: BackendApplicationClient(..., client_secret="...", ...)
      - pattern: $OAUTH.register(..., client_secret="...", ...)
    paths:
      exclude:
        - "**/test/**"
        - "**/test_*.py"
        - "**/*_test.py"
        - "**/conftest.py"
    metadata:
      oauthlint-rule-id: AUTH-PY-OAUTH-006
      oauthlint-doc-url: https://oauthlint.dev/rules/py-oauth-hardcoded-client-secret
      category: security
      cwe: CWE-798
      owasp: API2:2023
      llm-prevalence: HIGH
      technology:
        - authlib
        - requests-oauthlib
      references:
        - https://docs.authlib.org/en/latest/client/oauth2.html
        - https://cwe.mitre.org/data/definitions/798.html
