Safeguard
Application Security•

ASVS 5.0 V16.3.2: Log Failed Authorization Attempts

ASVS V16.3.2 requires failed authorization to be logged, and at Level 3 every decision and sensitive data access. Middleware example and test steps.

Safeguard Security Team
3 min read

ASVS 5.0 V16.3.2 requires that failed authorization attempts are logged. For Level 3, every authorization decision must be logged, including when sensitive data is accessed, without logging the sensitive data itself. The requirement is Level 2 for failed attempts. Put the logging in your central access check so no endpoint can skip it.

Why it matters

A burst of 403 responses against object ids is the signature of someone probing for broken access control, one of the most common web flaws. If denials leave no trace, you only learn about the attack after data has gone. Allowed decisions on sensitive records matter too, because they answer the question regulators ask after an incident: who looked at this record.

How to implement it

Log inside the single function that makes the decision.

import logging
log = logging.getLogger("authz")

SENSITIVE = {"medical_record", "payment_method", "salary"}

def authorize(user, action, resource_type, resource_id, allowed: bool):
    if not allowed:
        log.warning("authz.denied", extra={"fields": {
            "user_id": user.id, "action": action,
            "resource_type": resource_type, "resource_id": resource_id,
            "tenant": user.tenant_id, "roles": sorted(user.roles)}})
    elif resource_type in SENSITIVE:      # extra rule for Level 3
        log.info("authz.sensitive_access", extra={"fields": {
            "user_id": user.id, "action": action,
            "resource_type": resource_type, "resource_id": resource_id}})
    return allowed

Record who, what action, which resource and why it was denied. Log the resource id, never its contents. Alert on many denials from one user or address in a short window.

Teams that use a policy engine can emit the decision log there, so every service gets the same record format.

How to test it

  1. As a low privilege user, request another user's object and an admin only endpoint.
  2. Verify each denial appears in the logs with user, action and resource.
  3. For Level 3, read a sensitive record as an allowed user and confirm an access entry exists without the record's data.
  4. Search the logs for field values from the record. There should be none.
  5. Check that denials from every route, including APIs and background jobs, are covered.

Common mistakes

  • Logging denials only for the web UI and not the API.
  • Returning 404 to hide existence and logging nothing.
  • Writing denial logs per endpoint by hand, so some are missed.
  • Putting the sensitive value into the log to help debugging.

Quick check

Is logging successful sensitive access required at Level 2?

No. Level 2 asks for failed attempts. Logging all decisions and sensitive access is the Level 3 addition.

Should a 404 used to hide a resource be logged as a denial?

Yes. Log the internal decision even if the client sees a 404.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.