Invokable Control Element in Multi-Thread Context with non-Final Static Storable or Member Element
Description
Invokable Control Element in Multi-Thread Context with non-Final Static Storable or Member Element occurs when a function or method operates in a multi-threaded environment but owns an unsafe non-final static variable or mutable member data element. When multiple threads access and modify shared mutable state without proper synchronization, race conditions occur. These race conditions can lead to data corruption, inconsistent state, and unpredictable behavior that may have security implications.
Risk
This weakness creates reliability and security risks. Race conditions on security-critical data can lead to authentication bypasses, authorization failures, or data leaks. For example, a shared variable tracking authentication state could be corrupted, allowing unauthorized access. TOCTOU (Time-of-Check to Time-of-Use) vulnerabilities commonly arise from unsynchronized shared state. The non-deterministic nature of race conditions makes them difficult to detect through testing but can be reliably exploited. In security contexts, attackers may be able to trigger specific thread interleavings to exploit the vulnerability.
Solution
Use proper synchronization mechanisms: locks, mutexes, semaphores, or synchronized blocks. Make shared variables final/immutable where possible. Use thread-safe data structures (ConcurrentHashMap, AtomicInteger, etc.). Apply the principle of thread confinement - avoid sharing state between threads. Use volatile keyword for visibility (but not atomicity). Consider lock-free algorithms with atomic operations. Employ static analysis tools that detect threading issues. Use thread-safe design patterns like immutable objects or thread-local storage.
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability Reduce Reliability - Race conditions can cause crashes, hangs, or unpredictable behavior. |
| Integrity | Scope: Integrity Modify Application Data - Concurrent modifications without synchronization can corrupt shared data. |
| Access Control | Scope: Access Control Bypass Protection Mechanism - Race conditions on security state can lead to authentication/authorization bypasses. |
Example Code
Vulnerable Code
// Vulnerable: Non-final static variable in multi-threaded context
public class VulnerableSessionManager {
// Vulnerable: Mutable static shared across all threads
private static Map<String, Session> activeSessions = new HashMap<>();
// Vulnerable: Non-final static counter
private static int sessionCount = 0;
public static Session getSession(String sessionId) {
// Vulnerable: Unsynchronized read
// Another thread might be modifying the map concurrently
return activeSessions.get(sessionId);
}
public static void addSession(String sessionId, Session session) {
// Vulnerable: Check-then-act race condition
if (!activeSessions.containsKey(sessionId)) {
activeSessions.put(sessionId, session);
sessionCount++; // Non-atomic increment
}
}
public static void removeSession(String sessionId) {
// Vulnerable: Unsynchronized modification
if (activeSessions.containsKey(sessionId)) {
activeSessions.remove(sessionId);
sessionCount--; // Non-atomic decrement
}
}
}
// Race condition scenario:
// Thread 1: calls addSession("sess1", session1)
// Thread 2: calls addSession("sess1", session2) at same time
// Both check containsKey() -> false (race)
// Both add their session -> one overwrites the other
// sessionCount incremented twice but only one session exists
# Vulnerable: Shared mutable state in Python multi-threading
import threading
class VulnerableRateLimiter:
# Vulnerable: Shared mutable state without locking
request_counts = {} # Class variable shared by all instances/threads
total_requests = 0
def check_rate_limit(self, client_id, limit=100):
# Vulnerable: Read-modify-write without synchronization
current = self.request_counts.get(client_id, 0)
if current >= limit:
return False # Rate limited
# Race condition window here!
# Another thread could modify request_counts[client_id]
self.request_counts[client_id] = current + 1
self.total_requests += 1 # Non-atomic increment
return True
# Multiple threads checking rate limit can exceed the limit
# due to race condition between read and write
// Vulnerable: C++ with unsynchronized shared state
class VulnerableCache {
private:
// Vulnerable: Non-const static member modified by multiple threads
static std::map<std::string, std::string> cache;
static int hitCount;
static int missCount;
public:
static std::string get(const std::string& key) {
// Vulnerable: Unsynchronized read
auto it = cache.find(key);
if (it != cache.end()) {
hitCount++; // Race condition!
return it->second;
}
missCount++; // Race condition!
return "";
}
static void put(const std::string& key, const std::string& value) {
// Vulnerable: Unsynchronized write
cache[key] = value; // Iterator invalidation possible!
}
};
// Static member definitions
std::map<std::string, std::string> VulnerableCache::cache;
int VulnerableCache::hitCount = 0;
int VulnerableCache::missCount = 0;
// Vulnerable: C# with shared mutable state
public class VulnerableAuthenticationState
{
// Vulnerable: Non-readonly static fields
private static Dictionary<string, User> authenticatedUsers = new Dictionary<string, User>();
private static int failedLoginAttempts = 0;
public static bool IsAuthenticated(string token)
{
// Vulnerable: Dictionary not thread-safe
return authenticatedUsers.ContainsKey(token);
}
public static void Authenticate(string token, User user)
{
// Vulnerable: Race condition
if (!authenticatedUsers.ContainsKey(token))
{
authenticatedUsers[token] = user;
}
}
public static void RecordFailedLogin()
{
// Vulnerable: Non-atomic increment
failedLoginAttempts++;
// Could miss counting some failures due to race
if (failedLoginAttempts > 10)
{
TriggerAlert();
}
}
}
Fixed Code
// Fixed: Proper synchronization for multi-threaded context
public class FixedSessionManager {
// Fixed: Use ConcurrentHashMap for thread-safe operations
private static final ConcurrentHashMap<String, Session> activeSessions =
new ConcurrentHashMap<>();
// Fixed: Use AtomicInteger for thread-safe counting
private static final AtomicInteger sessionCount = new AtomicInteger(0);
public static Session getSession(String sessionId) {
// Fixed: ConcurrentHashMap is thread-safe
return activeSessions.get(sessionId);
}
public static void addSession(String sessionId, Session session) {
// Fixed: Atomic putIfAbsent operation
Session existing = activeSessions.putIfAbsent(sessionId, session);
if (existing == null) {
// Only increment if we actually added a new session
sessionCount.incrementAndGet();
}
}
public static void removeSession(String sessionId) {
// Fixed: Atomic remove returns the removed value
Session removed = activeSessions.remove(sessionId);
if (removed != null) {
sessionCount.decrementAndGet();
}
}
public static int getSessionCount() {
return sessionCount.get();
}
}
// Alternative: Using synchronized blocks
public class FixedSessionManagerSynchronized {
private static final Map<String, Session> activeSessions = new HashMap<>();
private static int sessionCount = 0;
private static final Object lock = new Object();
public static Session getSession(String sessionId) {
synchronized (lock) {
return activeSessions.get(sessionId);
}
}
public static void addSession(String sessionId, Session session) {
synchronized (lock) {
if (!activeSessions.containsKey(sessionId)) {
activeSessions.put(sessionId, session);
sessionCount++;
}
}
}
}
# Fixed: Thread-safe implementation with locks
import threading
from collections import defaultdict
class FixedRateLimiter:
def __init__(self):
# Fixed: Instance variables with lock protection
self._request_counts = defaultdict(int)
self._total_requests = 0
self._lock = threading.Lock()
def check_rate_limit(self, client_id, limit=100):
# Fixed: Acquire lock for entire check-and-update operation
with self._lock:
current = self._request_counts[client_id]
if current >= limit:
return False
self._request_counts[client_id] = current + 1
self._total_requests += 1
return True
def get_request_count(self, client_id):
with self._lock:
return self._request_counts[client_id]
# Alternative: Using threading.local for thread-confined state
class ThreadLocalRateLimiter:
_thread_local = threading.local()
@classmethod
def _get_counts(cls):
if not hasattr(cls._thread_local, 'counts'):
cls._thread_local.counts = defaultdict(int)
return cls._thread_local.counts
def check_rate_limit(self, client_id, limit=100):
counts = self._get_counts()
# No lock needed - thread-local storage
if counts[client_id] >= limit:
return False
counts[client_id] += 1
return True
// Fixed: C++ with proper synchronization
#include <mutex>
#include <shared_mutex>
#include <atomic>
class FixedCache {
private:
// Fixed: Mutable for use with const methods
mutable std::shared_mutex cacheMutex;
std::map<std::string, std::string> cache;
// Fixed: Atomic counters
std::atomic<int> hitCount{0};
std::atomic<int> missCount{0};
public:
std::string get(const std::string& key) {
// Fixed: Shared lock for concurrent reads
std::shared_lock<std::shared_mutex> lock(cacheMutex);
auto it = cache.find(key);
if (it != cache.end()) {
hitCount.fetch_add(1, std::memory_order_relaxed);
return it->second;
}
missCount.fetch_add(1, std::memory_order_relaxed);
return "";
}
void put(const std::string& key, const std::string& value) {
// Fixed: Exclusive lock for writes
std::unique_lock<std::shared_mutex> lock(cacheMutex);
cache[key] = value;
}
int getHitCount() const {
return hitCount.load(std::memory_order_relaxed);
}
};
// Fixed: Thread-safe C# implementation
public class FixedAuthenticationState
{
// Fixed: Use ConcurrentDictionary
private static readonly ConcurrentDictionary<string, User> authenticatedUsers =
new ConcurrentDictionary<string, User>();
// Fixed: Use Interlocked for atomic operations
private static int failedLoginAttempts = 0;
public static bool IsAuthenticated(string token)
{
// Fixed: ConcurrentDictionary is thread-safe
return authenticatedUsers.ContainsKey(token);
}
public static bool Authenticate(string token, User user)
{
// Fixed: TryAdd is atomic
return authenticatedUsers.TryAdd(token, user);
}
public static void RecordFailedLogin()
{
// Fixed: Interlocked.Increment is atomic
int currentAttempts = Interlocked.Increment(ref failedLoginAttempts);
if (currentAttempts > 10)
{
TriggerAlert();
}
}
public static void ResetFailedLoginCount()
{
Interlocked.Exchange(ref failedLoginAttempts, 0);
}
}
CVE Examples
Race conditions related to unsynchronized shared state have contributed to many vulnerabilities, though this specific CWE is often categorized under CWE-362 (Concurrent Execution) for CVE mapping purposes.
Related CWEs
- CWE-662: Improper Synchronization (parent)
- CWE-557: Concurrency Issues (category member)
- CWE-362: Concurrent Execution Using Shared Resource with Improper Synchronization (related)
References
- MITRE Corporation. "CWE-1058: Invokable Control Element in Multi-Thread Context with non-Final Static Storable or Member Element." https://cwe.mitre.org/data/definitions/1058.html
- Oracle. "Java Concurrency Tutorial."
- Goetz, Brian. "Java Concurrency in Practice."