Fail-Open Vulnerabilities

Fail-open vulnerabilities occur when applications default to allowing access or trusting input when security checks fail or logic errors occur.

The opposite of proper security is "fail-open" — when something goes wrong, the system defaults to allowing everything instead of denying everything. This is the most dangerous category of logic errors because it actively weakens security.


Real-World Attack Scenarios

Scenario 1: Failing Open on Authorization Check (CWE-636)

An application checks if user is admin:

def delete_user(user_id):
    # Check if current user is admin
    try:
        is_admin = check_admin_status()
    except:
        # FAIL OPEN - Assume admin on error!
        pass
    
    # No check if is_admin is True!
    # If exception, is_admin is undefined!
    
    # Proceed with deletion
    db.delete_user(user_id)
    return {"status": "User deleted"}

The vulnerability:

If check_admin_status() throws exception:

  • Exception caught but not handled properly

  • is_admin undefined

  • Code proceeds anyway

  • User deleted even though authorization failed

The attack:

Attacker sends request while admin check service is down:

Admin check service fails with connection error:

  • Exception thrown

  • Caught and ignored (pass statement)

  • Code proceeds anyway

  • User 42 deleted by non-admin attacker

Result:

  • Complete authorization bypass

  • Unauthorized admin actions

  • Data deletion

  • Service unavailable = security disabled

The fix:

Fail securely (default deny):

Finding it: Look for try/except blocks that catch security checks. Check if exception handling leads to access grant rather than denial.


Scenario 2: Missing Break Statement in Switch (CWE-484)

User role authorization check missing break:

The vulnerability:

Missing break causes fall-through:

  • role = "user" sets accessLevel = 1

  • Falls through to admin case

  • Overrides with accessLevel = 10

  • User becomes admin!

The attack:

Attacker registers as regular user, then somehow triggers the "user" case followed by admin case:

Result:

  • Privilege escalation

  • Regular user becomes admin

  • Unauthorized access

The fix:

Always include break statements:

Finding it: Search for switch statements without break. Use compiler warnings. Test for fall-through behavior.


Scenario 3: Missing Default Case (CWE-478)

Payment status check missing default case:

The vulnerability:

No default case for unexpected values:

  • status = "approved" → Delivers (correct)

  • status = "declined" → Declines (correct)

  • status = "pending"Falls through, does nothing

  • status = "refund"Falls through, does nothing

  • status = "invalid"Falls through, does nothing

Attacker sends status = "pending":

  • No delivery

  • No payment charge

  • Free product

The attack:

Attacker modifies API call:

Result:

  • Free products

  • Revenue loss

  • Fraud

The fix:

Always have default case:

Or use explicit state machine:

Finding it: Look for if/elif chains without else. Look for switch statements without default. Check for unhandled enum values.


Scenario 4: NULL Pointer Dereference (CWE-476)

User authorization check returns NULL:

The vulnerability:

If getCurrentUserId() returns invalid ID:

  • findUserById() returns null

  • user.isAdmin() throws NullPointerException

  • Exception caught and ignored

  • Authorization check fails silently

  • Code continues anyway

  • User deletion proceeds without authorization check

The attack:

Attacker sends request with invalid user ID:

  • findUserById("invalid") returns null

  • isAdmin() throws NullPointerException

  • Exception silently caught

  • deleteUser() proceeds

  • User deleted without proper authorization

Result:

  • Authorization bypass

  • Unauthorized deletion

  • Data destruction

The fix:

Always check for null:

Finding it: Search for method calls without null checks. Use static analysis tools (FindBugs, Checkstyle). Enable compiler warnings for null dereferences.


Scenario 5: Divide By Zero (CWE-369)

Price calculation with user-provided denominator:

Normal case:

The attack:

Attacker provides 0 discount:

Actually, divide by zero needs different scenario. Better example:

The attack:

Attacker provides 0 items:

Result:

  • Divide by zero exception

  • Application crash

  • Denial of service

The fix:

Validate input:

Finding it: Look for division operations. Check if denominator is validated. Test with zero values.


Scenario 6: Inverted Authorization Logic

Authorization check logic accidentally inverted:

The vulnerability:

Logic is backwards:

  • If user_id == current_user.id → Deny (your own profile)

  • If user_id != current_user.id → Allow (someone else's profile)

The attack:

Attacker gets other user's ID (123) and modifies their profile:

Authorization check:

  • user_id = 123 (victim)

  • current_user.id = 456 (attacker)

  • 123 != 456 → Allow!

  • Attacker modifies victim's profile

Result:

  • Account takeover

  • Profile defacement

  • Email change

  • Password reset

The fix:

Correct the logic:

Finding it: Review authorization logic carefully. Test with unauthorized users. Look for inverted conditions (not equals instead of equals).


Scenario 7: Default Allow in Access Control

Access control matrix with missing entries defaults to allow:

The vulnerability:

Actually, this one defaults to deny. Better example:

The attack:

Attacker sends empty or null role:

Result:

  • Complete authorization bypass

  • Unauthorized access

  • Admin actions as non-admin

The fix:

Always validate and fail securely:

Finding it: Review access control logic. Check for default allow. Look for missing validation. Test with null/empty values.


Mitigation Strategies

Fail secure (default deny)

Validate all input

Check for null/empty

Use explicit state machines

Comprehensive exception handling

Code review

  • Review all authorization logic

  • Check switch statements for break

  • Verify all cases handled

  • Test error paths

Static analysis

  • Use FindBugs, Checkstyle, SonarQube

  • Check for null dereferences

  • Check for missing cases

  • Check for fall-through


Last updated