Safeguard
Application Security•

ASVS 5.0 V15.4.1: Protect Shared State From Race Conditions

ASVS V15.4.1 (Level 3) requires thread safe types and locks for shared caches, files and objects. Examples in Java and Go, plus a race detector test.

Safeguard Security Team
3 min read

ASVS 5.0 V15.4.1 requires that shared objects in multi threaded code, such as caches, files and in memory state, are accessed with thread safe types and synchronization like locks or semaphores, to avoid race conditions and corrupted data. It is Level 3. Share as little as possible, and when you must share, guard every access path.

Why it matters

A race condition is a security bug when the shared data is a session, a balance, a permission cache or a rate limit counter. Two requests interleave and one reads a stale value, so a limit is exceeded or a check is skipped. These bugs are intermittent, which is why they survive testing and show up under attacker load.

How to implement it

Prefer concurrency safe types over hand rolled locking.

// Java: atomic, lock free counter and a concurrent map
private final ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();
private final AtomicInteger failures = new AtomicInteger();

Session s = sessions.computeIfAbsent(id, k -> loadSession(k)); // atomic

When several fields must change together, use one lock for all of them:

type Wallet struct {
    mu      sync.Mutex
    balance int64
}

func (w *Wallet) Debit(n int64) error {
    w.mu.Lock()
    defer w.mu.Unlock()
    if w.balance < n {
        return errors.New("insufficient funds")
    }
    w.balance -= n
    return nil
}

The check and the update sit inside one critical section. Hold locks for the shortest time possible and never call unknown code while holding one.

How to test it

Run tests under a race detector: go test -race ./..., ThreadSanitizer for C and C++, or the equivalent for your runtime. Then add a stress test that fires many concurrent operations at one object and asserts an invariant, such as the balance never going negative. Run it hundreds of times.

Common mistakes

  • Protecting writes with a lock but reading without one.
  • Using a thread safe map and then doing check then insert as two steps.
  • Sharing a non thread safe object, such as a date formatter, between requests.
  • Assuming a single process deployment when autoscaling runs several.

Quick check

Does a thread safe collection make my logic safe?

No. Each call is safe, but a sequence of calls is not unless you use an atomic compound operation or a lock.

Which level is this?

Level 3.

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.