Skip to content

CWE-274: Improper Handling of Insufficient Privileges

Overview

Improper handling of insufficient privileges happens when a product runs into an operation it lacks the rights to perform - a file it can't read, a resource it can't modify, an action the OS or platform denies - and responds badly to that denial: falling back to an insecure alternative, exposing the denied path or credential in an error message, or letting execution continue as if the operation had succeeded. The weakness is not the missing privilege itself; it's how the code reacts once it discovers it doesn't have what it needs.

Relationship to Other CWEs

MITRE marks CWE-274 Discouraged for mapping new findings: it substantially overlaps CWE-280 (Improper Handling of Insufficient Permissions or Privileges), which also has no page here, and may be deprecated in a future CWE release. If you are triaging a new finding rather than working from an existing CWE-274 tag, CWE-280 is the closer fit. Reaching for the parents instead does not help, because MITRE marks CWE-269 Discouraged as well. The guidance on this page still applies to any finding already tagged CWE-274.

OWASP Classification

A10:2025 - Mishandling of Exceptional Conditions

Risk

Medium: poor handling of a privilege denial leads to information disclosure, where an error message reveals the file path, username, or permission model an attacker is probing; a security bypass through an insecure fallback, such as writing to a world-writable location when the intended path is denied; or an unhandled-exception crash. It also blurs the line between authentication, "you're not who you say you are", and authorization, "you are who you say you are, but you can't do this", which need different responses.

Remediation Steps

Core Principle: When the platform denies the product an operation it needs, fail closed on that denial - never fall back to a less-restricted alternative and never leak the denial's details to the caller.

Trace the Operation

  • Source: Any operation that can be denied because the identity the product runs as lacks sufficient rights - a file open, a privileged syscall, binding a port, an administrative API call made with the service's own credentials.
  • Sink: The response path the code takes once the denial happens - what it returns to the caller, what it logs, and what it tries next.
  • Missing control: No explicit handling of the denial when it happens, a handler that leaks detail or falls back to something less secure, or a process that starts without the rights it needs and only discovers that under load.

Fail Closed When the Operation Is Denied (Primary Defense)

Any operation against a resource the product does not fully control can be denied at the moment it runs - the file's mode changed, the container dropped the capability, the platform restriction wasn't what the code modelled. Treat that denial as fatal for the operation, not as something to route around:

// SECURE - pseudo-code
try:
    perform(resource, action)
except PermissionDenied:
    log_denial_with_full_detail_server_side()
    return generic_error_response()   // no path, identity, or platform detail
// never: fall back to a less-restricted resource or location

Never catch a permission denial and retry against a more permissive fallback - a world-writable temp path, a cached copy, a default account - that turns an enforced restriction into an optional one. This is the control that has to hold, because it's the only one that runs at the moment the operation is attempted.

Check the Product's Own Capability Early (Optimization, Not the Control)

Where the product needs a specific right to function at all - a config file it must read, a port it must bind, a directory it must write to - probe for it at startup rather than discovering it mid-request:

// SECURE - pseudo-code
for resource, action in required_capabilities:
    if not can_perform(resource, action):
        log_startup_failure(resource, action)
        exit_with_configuration_error()   // refuse to start degraded

This turns a confusing runtime failure into a clear refusal to start, and stops the process running in a half-working state where some requests silently take a fallback path. It does not enforce anything: a right that exists at startup can be revoked before the request that needs it, so the handler above still has to be there.

Scope note, because this page and the authorization CWEs get filed together. If the finding is about the authorization decision - whether the caller should have been allowed, and where that gets enforced - that is CWE-285 and CWE-863. What this page owns is what the product does once a privilege it needs is refused: how the denial is handled, and how it is surfaced. The response-shaping guidance below applies whichever of the two produced the denial, which is why it names the caller-facing status codes.

Return Generic, Consistent Error Responses

Log the full detail server-side for diagnosis and keep it out of the response: no file path, account name, or platform permission detail in the body.

Whether the response should distinguish "doesn't exist" from "not allowed" depends on the resource. Where the existence of the resource is itself sensitive - another tenant's record ID, a private document, an account looked up by email address - collapse both cases into a single 404 so the response can't be used to enumerate what exists. Elsewhere the distinct statuses carry correct and useful meaning, and CWE-285 keeps them: 401 for an unauthenticated caller, 403 for an authenticated caller without the permission, 404 for a resource that genuinely isn't there.

Test with Denied and Unexpected Permission States

  • Force the underlying operation to be denied - remove the file's read bit, drop the capability, revoke the account's grant - and confirm the response is generic: no file path, username, or permission-system detail in the body.
  • Deny the operation after the startup capability check has already passed, and confirm there's no fallback to a less-restricted path and no continuation as if it had succeeded.
  • Start the process without one of the rights it requires and confirm it refuses to start rather than serving requests in a degraded state.
  • Where the resource's existence is itself sensitive, compare the response for "doesn't exist" against "exists but access is denied" - they should be indistinguishable to the caller. Where it isn't, confirm 401, 403 and 404 are each returned for the right condition.
  • Re-scan with the security scanner to confirm the finding is resolved.

Common Vulnerable Patterns

  • Letting the platform's permission error propagate unhandled, so the denial surfaces as a crash or a stack trace instead of a deliberate response
  • Catching a permission-denied error and falling back to a less-restricted resource or location
  • Including the denied file path, username, or permission detail directly in the response sent to the caller
  • Returning different responses for "not found" versus "access denied" on a resource whose existence is itself sensitive, letting an attacker enumerate what exists
  • Continuing execution after a permission check fails instead of stopping

Common Pitfalls

  • Trusting the pre-check instead of the operation's own result: a capability probe or permission check answers for the value it was given at the moment it ran. The code then builds the actual path from a different input, or the right is revoked between the check and the use. Either way the check passed and the operation still fails - which is why the denial handler is the control and the pre-check is only an early exit.
  • Treating a caught exception as "handled" without stopping execution: wrapping the operation in a try/catch that logs the permission error but then falls through into code written assuming the operation succeeded, rather than returning immediately.
  • Silencing the error instead of failing closed: returning a default or empty result when a permission check fails, which can look like "no data" to the caller instead of "access denied," and lets calling code proceed as if the request succeeded.

Additional Resources