Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.
Why this matters
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.
VULNERABLE
vulnerable.py
"""Flask views that leak OAuth credentials from the request into logs."""import loggingfrom flask import Flask, requestapp = Flask(__name__)logger = logging.getLogger(__name__)@app.route("/callback")def callback(): # Authorization code from the callback printed directly. # ruleid: auth.py.flow.oauth-credential-in-log print(request.args.get("code")) return "ok"@app.route("/exchange")def exchange(): # access_token assigned to a local, then logged (indirection). access_token = request.args.get("access_token") # ruleid: auth.py.flow.oauth-credential-in-log logger.info("token exchange complete: %s", access_token) return "ok"@app.route("/introspect")def introspect(): # Raw Authorization header logged on failure. # ruleid: auth.py.flow.oauth-credential-in-log logging.error("auth failed for %s", request.headers.get("Authorization")) return "ok"@app.route("/refresh")def refresh(): # refresh_token from the form body logged via logger.debug. refresh_token = request.form["refresh_token"] # ruleid: auth.py.flow.oauth-credential-in-log logger.debug(refresh_token) return "ok"
SAFE
safe.py
"""Flask views that log safely — no OAuth credential reaches a log sink."""import loggingfrom flask import Flask, requestapp = Flask(__name__)logger = logging.getLogger(__name__)def redact(value): """Return only a short, non-sensitive prefix of a credential.""" return (value[:4] + "...") if value else value@app.route("/ping")def ping(): # Constant status message — no request data, no taint. print("oauth callback received") return "ok"@app.route("/list")def list_items(): # Benign request field (pagination) — not a credential source. logger.info("listing page %s", request.args.get("page")) return "ok"@app.route("/callback")def callback(): # Sanitized: the authorization code is redacted before logging. code = request.args.get("code") logger.info("code prefix %s", redact(code)) return "ok"
Suppressing this rule
If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.