Race Conditions

Race conditions (CWE-362) occur when code doesn't properly synchronize access to shared resources, allowing multiple concurrent operations to interfere with each other. The most common variant is Time-of-Check-Time-of-Use (TOCTOU), where a check is performed, then a resource is used, but the resource changes between the check and use.


Real-World Attack Scenarios

Scenario 1: TOCTOU in File Access

A file operation checks ownership then accesses the file:

def delete_file(filename):
    # CHECK: Verify user owns file
    if not user_owns_file(filename):
        raise PermissionDenied()
    
    # TIME WINDOW - Attacker can act here!
    
    # USE: Delete the file
    os.remove(filename)

The vulnerability:

Between check and use, attacker can modify the file (symlink attack):

Thread 1 (victim):
1. Check: user_owns_file("/home/user/myfile.txt") → True
2. [Context switch]

Thread 2 (attacker):
3. Replace symlink: ln -sf /etc/passwd /home/user/myfile.txt

Thread 1 continues:
4. Use: os.remove("/home/user/myfile.txt")
5. ACTUALLY DELETES: /etc/passwd!

The attack:

Result:

  • Delete system files

  • Modify critical files

  • Privilege escalation

  • System compromise

Finding it: Identify file operations. Try racing with symlinks. Monitor system files for unexpected modifications.


Scenario 2: TOCTOU in Balance Checks

Bank application checks balance before allowing withdrawal:

The vulnerability:

Between check and use, another withdrawal can occur:

The attack:

  1. User has $100

  2. Attacker (or accomplice) makes two simultaneous $100 withdrawals

  3. Both pass balance check

  4. Both execute withdrawal

  5. Account balance is now -$100

  6. Attacker steals money

Result:

  • Money theft

  • Account goes negative

  • Bank loses money

  • System inconsistency

Finding it: Identify balance check operations. Make simultaneous requests. Check if both succeed.


Scenario 3: TOCTOU in Permission Changes

Admin changes user permissions:

The vulnerability:

Attacker changes their own role between check and promotion:

Result:

  • Privilege escalation

  • Attacker becomes admin

  • Complete system control


Scenario 4: Check-After-Action Race

Application performs action then checks if it should have:

The vulnerability:

Action happens before permission check!

Result:

  • Users delete accounts they shouldn't have access to

  • Data loss

  • System inconsistency


Scenario 5: Inventory Race Condition

E-commerce checks stock before selling:

The vulnerability:

Multiple customers buy simultaneously from limited stock:

Result:

  • Overselling

  • Unfulfilled orders

  • Revenue loss

  • Customer complaints

Finding it: Purchase items simultaneously. Monitor inventory. Check if overselling possible.


How to Identify Race Conditions During Testing

1. Identify potential race windows

Look for patterns:

  • Check then use

  • Check then modify

  • Multiple step operations

  • Database operations without transactions

2. Test with concurrent requests

Use threading or multiple processes:

3. Use timing attacks

Deliberately delay operations to increase race window:

4. Monitor for inconsistent state

After concurrent operations, check if state is consistent:

  • Total balance correct?

  • Inventory counts correct?

  • Permissions properly assigned?

5. Use race condition testing tools

  • Apache JMeter for load testing

  • Burp Intruder for repeating requests

  • Custom scripts for precise timing

6. Analyze transaction handling

Check if operations are atomic:


Mitigation Strategies

Use atomic operations

Ensure check and use happen atomically:

Use database transactions

Use locks and synchronization

Use optimistic locking

Add version/timestamp to prevent concurrent modifications:

Avoid symlink attacks

Use secure file handling:

Use file locking


Last updated