agentleFS
scholarly360scholarly360/owasp-top10-web-skills/skills/security-logging-alerting-failures/SKILL.md

security-logging-alerting-failures

Skill23 starsChanged 7 months agoMITView on GitHub

Use this skill whenever auditing, reviewing, or testing Python web applications (FastAPI or Flask) for OWASP A09:2025 — Security Logging & Alerting Failures. Trigger this skill when the user mentions: logging security, audit trails, log injection, sensitive data in logs, alerting gaps, insufficient logging, SIEM integration, log monitoring, incident detection readiness, or any request to audit or fix logging/alerting in a Python backend. Also trigger when a user asks "are we logging the right things?", "how do I detect attacks?", or "what should we be alerting on?". Do NOT skip this skill just because the request sounds simple — log-related security issues are consistently underestimated and require systematic coverage across all five CWEs.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run these tools as part of CI/CD:

    line 225
  2. Distinctive:

    Read these when the user needs detailed implementation help beyond the checklist.

    line 260

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

A09:2025 — Security Logging & Alerting Failures

OWASP rank: #9 (community-voted for third consecutive cycle)
Renamed in 2025: Added "Alerting" — logging without alerting provides minimal security value.
Stats: 5 CWEs, 723 CVEs, 3.91% average incidence rate
Coverage CWEs: CWE-778, CWE-117, CWE-532, CWE-223, CWE-390


What This Category Covers

Failure TypeDescription
Insufficient LoggingAuditable events (logins, access control failures, validation errors) not logged
Log InjectionUser input flows unescaped into log messages — enables log forgery
Sensitive Data in LogsPasswords, tokens, PII, card numbers written to log output
Omission of Security-Relevant InfoErrors/warnings logged without context (IP, user, timestamp, action)
No AlertingLogs exist but no thresholds, rules, or platform routes them to incident response

Audit Checklist — FastAPI & Flask

Work through each section systematically. For each item, note: PASS, FAIL, or NOT APPLICABLE.

1. Log Injection (CWE-117)

User-controlled input must never flow raw into log statements.

What to look for:

# VULNERABLE — newline injection, ANSI escape injection
logger.info(f"User logged in: {request.form['username']}")
logger.warning("Failed login for: " + username)

# SAFE — sanitize before logging
import re
safe_username = re.sub(r'[\r\n\x1b]', '_', username)
logger.info("Failed login for: %s", safe_username)

Checklist:

  • No f-strings or + concatenation with raw request data in log calls
  • Newlines (\r, \n) stripped from all user-supplied log values
  • ANSI escape codes (\x1b[) stripped (prevent terminal injection)
  • Structured logging used (JSON format) — field separation prevents injection by design

2. Sensitive Data in Logs (CWE-532)

Secrets must never appear in log output — even at DEBUG level.

Patterns to flag:

# VULNERABLE
logger.debug(f"Auth token: {token}")
logger.info(f"Processing payment for card: {card_number}")
app.logger.debug(request.json)         # May contain password field
print(f"Password reset for {email}, token={reset_token}")

# SAFE
logger.info("Auth token validated for user_id=%s", user_id)
logger.info("Payment processed for user_id=%s, last4=%s", user_id, card_number[-4:])

What to scan for:

  • No logging of: password, passwd, secret, token, api_key, authorization header values
  • No logging of: credit card numbers, SSNs, full email+password combos
  • request.json / request.form not logged wholesale without field filtering
  • No print() statements containing sensitive variables in production code
  • Bandit rule B506 (and similar) passes in CI/CD

3. Insufficient Logging (CWE-778)

The following events must produce log entries with full context.

Required log events:

EventMinimum Fields
Failed authenticationtimestamp, IP, username attempted, user-agent
Successful authenticationtimestamp, IP, user_id, method (password/OAuth/MFA)
Authorization failure (403)timestamp, IP, user_id, resource attempted, HTTP method
Input validation failuretimestamp, IP, user_id, field name (not value if sensitive), error
High-value transactiontimestamp, user_id, action, resource ID, before/after state
Account changes (password reset, role change)timestamp, actor_user_id, target_user_id, change type
Admin actionstimestamp, admin_user_id, action, affected resource

FastAPI implementation pattern:

import logging
import structlog  # recommended for structured logs

log = structlog.get_logger()

# In auth endpoint
@router.post("/login")
async def login(credentials: LoginSchema, request: Request):
    user = await authenticate(credentials)
    if not user:
        log.warning(
            "auth.failed",
            ip=request.client.host,
            username=credentials.username,    # OK — username is not a secret
            user_agent=request.headers.get("user-agent"),
        )
        raise HTTPException(status_code=401, detail="Invalid credentials")
    log.info("auth.success", user_id=user.id, ip=request.client.host)

Flask implementation pattern:

from flask import request
import logging

@app.route("/login", methods=["POST"])
def login():
    user = authenticate(request.form["username"], request.form["password"])
    if not user:
        app.logger.warning(
            "auth.failed ip=%s username=%s ua=%s",
            request.remote_addr,
            request.form.get("username"),
            request.user_agent.string,
        )
        return {"error": "Invalid credentials"}, 401

Checklist:

  • All 401/403 responses have a corresponding logger.warning() or logger.error() call
  • Log entries include: timestamp (automatic with logging), source IP, user identifier
  • Password reset and account modification flows are logged
  • Admin panel actions are logged with actor identity
  • High-value business transactions produce audit log entries

4. Structured Logging & SIEM Compatibility

Log format must be parseable by observability platforms (ELK, Splunk, Datadog, Sentry).

FastAPI — structlog + JSON:

# main.py
import structlog
import logging

structlog.configure(
    processors=[
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.stdlib.add_log_level,
        structlog.processors.JSONRenderer(),  # machine-parseable
    ],
    wrapper_class=structlog.BoundLogger,
    logger_factory=structlog.PrintLoggerFactory(),
)

Flask — python-json-logger:

from pythonjsonlogger import jsonlogger

handler = logging.StreamHandler()
handler.setFormatter(jsonlogger.JsonFormatter(
    fmt="%(asctime)s %(levelname)s %(name)s %(message)s"
))
app.logger.addHandler(handler)

Checklist:

  • Log output is JSON-formatted (not plain text) in production
  • Log level is not DEBUG in production (leaks verbose info)
  • Logs ship to a centralized platform: Sentry, ELK, Splunk, Datadog, CloudWatch
  • Log retention policy exists and meets compliance requirements (e.g., 90 days minimum)

5. Alerting Integration

Logging without alerting = silent failures. Verify active monitoring exists.

Sentry (exception alerting):

# FastAPI
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
sentry_sdk.init(dsn=settings.SENTRY_DSN, integrations=[FastApiIntegration()])

# Flask
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init(dsn=settings.SENTRY_DSN, integrations=[FlaskIntegration()])

Recommended alerting thresholds:

SignalAlert Trigger
Failed logins>10 failures for same username in 5 min
Failed logins>100 failures from same IP in 5 min
403 responses>50 from same user_id in 1 min
500 errors>5% of requests in any 1-min window
New admin accountImmediate alert, every occurrence
Privilege escalationImmediate alert, every occurrence

Checklist:

  • Sentry or equivalent is initialized and receiving events in production
  • Rate-limit violations produce alert events (not just HTTP 429 responses)
  • Repeated auth failures trigger alerts (brute force detection)
  • Alerting runbooks/playbooks exist for each alert type
  • Honeytokens deployed in high-value areas (near-zero false-positive intrusion detection)

Automated Scanning

Run these tools as part of CI/CD:

# Static analysis — catches log injection patterns, sensitive data in logs
bandit -r . -t B106,B107,B110 --severity-level medium

# Search for raw request data in log calls
grep -rn "logger\.\(info\|warning\|error\|debug\)" . \
  | grep -E "request\.(form|json|args|data|headers)\[" \
  | grep -v "\.get(" 

# Search for potential sensitive field logging
grep -rn "logger\|logging\|print" . \
  | grep -iE "password|passwd|secret|token|api_key|card|ssn|cvv"

Key CWEs Reference

CWENamePython Risk
CWE-778Insufficient LoggingNo logging on auth/authz failures
CWE-117Log Injectionf-string user input in logger calls
CWE-532Sensitive Info in LogsPasswords/tokens in debug output
CWE-223Omission of Security-Relevant InfoLogs lack IP/user context
CWE-390Detection of Error Condition Without ActionException caught, swallowed, not logged

Reference Files

  • references/remediation-patterns.md — Full before/after code fixes for each CWE
  • references/alerting-platforms.md — Integration guides for Sentry, ELK, Splunk, Datadog

Read these when the user needs detailed implementation help beyond the checklist.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.