BUG-HUNT: [concurrency] Settings.get_settings() classmethod has TOCTOU race on _instance class variable #7634

Open
opened 2026-04-11 00:34:07 +00:00 by HAL9000 · 1 comment
Owner

Bug Report: [concurrency] — Settings.get_settings() TOCTOU Race

Severity Assessment

  • Impact: Settings.get_settings() and get_settings() use a class-level _instance variable with a TOCTOU check. Two concurrent callers can both evaluate cls._instance is None as True and both create Settings() instances. The second write overwrites the first. Callers that saved the reference from the first creation now have a stale Settings instance that is no longer the cached singleton.
  • Likelihood: Low — primarily a startup race condition.
  • Priority: Low

Location

  • File: src/cleveragents/config/settings.py
  • Function/Class: Settings.get_settings
  • Lines: 716-720

Description

@classmethod
def get_settings(cls) -> Settings:
    if cls._instance is None:   # TOCTOU check
        cls._instance = cls()   # TOCTOU write
    return cls._instance

Thread A and Thread B can both see _instance is None before either creates the instance. The second creation overwrites the first, and Thread A returns a stale instance.

Evidence

# settings.py lines 716-720
@classmethod
def get_settings(cls: type[Settings]) -> Settings:
    if cls._instance is None:  # TOCTOU
        cls._instance = cls()  # TOCTOU write
    return cls._instance

Expected Behavior

Use a class-level threading.Lock to protect the check-and-set.

Actual Behavior

Concurrent callers can get different Settings instances.

Suggested Fix

_instance_lock: ClassVar[threading.Lock] = threading.Lock()

@classmethod
def get_settings(cls) -> Settings:
    if cls._instance is None:  # Fast path without lock
        with cls._instance_lock:
            if cls._instance is None:  # Double-checked locking
                cls._instance = cls()
    return cls._instance

Category

concurrency

TDD Note

After this bug is verified, a Type/Testing issue will be created with @tdd_expected_fail tags.


Automated by CleverAgents Bot
Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor

## Bug Report: [concurrency] — Settings.get_settings() TOCTOU Race ### Severity Assessment - **Impact**: `Settings.get_settings()` and `get_settings()` use a class-level `_instance` variable with a TOCTOU check. Two concurrent callers can both evaluate `cls._instance is None` as True and both create `Settings()` instances. The second write overwrites the first. Callers that saved the reference from the first creation now have a stale Settings instance that is no longer the cached singleton. - **Likelihood**: Low — primarily a startup race condition. - **Priority**: Low ### Location - **File**: src/cleveragents/config/settings.py - **Function/Class**: Settings.get_settings - **Lines**: 716-720 ### Description ```python @classmethod def get_settings(cls) -> Settings: if cls._instance is None: # TOCTOU check cls._instance = cls() # TOCTOU write return cls._instance ``` Thread A and Thread B can both see `_instance is None` before either creates the instance. The second creation overwrites the first, and Thread A returns a stale instance. ### Evidence ```python # settings.py lines 716-720 @classmethod def get_settings(cls: type[Settings]) -> Settings: if cls._instance is None: # TOCTOU cls._instance = cls() # TOCTOU write return cls._instance ``` ### Expected Behavior Use a class-level threading.Lock to protect the check-and-set. ### Actual Behavior Concurrent callers can get different Settings instances. ### Suggested Fix ```python _instance_lock: ClassVar[threading.Lock] = threading.Lock() @classmethod def get_settings(cls) -> Settings: if cls._instance is None: # Fast path without lock with cls._instance_lock: if cls._instance is None: # Double-checked locking cls._instance = cls() return cls._instance ``` ### Category concurrency ### TDD Note After this bug is verified, a Type/Testing issue will be created with @tdd_expected_fail tags. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor
HAL9000 added this to the v3.5.0 milestone 2026-04-11 00:51:35 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Backlog — Settings.get_settings() TOCTOU race on _settings singleton. Low-risk in practice.
  • Milestone: v3.5.0 (M6: Autonomy Hardening) — Settings infrastructure
  • Story Points: 2 (S) — Thread safety fix
  • MoSCoW: Could Have — Minor race condition, not blocking

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

Issue triaged by project owner: - **State**: Verified - **Priority**: Backlog — Settings.get_settings() TOCTOU race on _settings singleton. Low-risk in practice. - **Milestone**: v3.5.0 (M6: Autonomy Hardening) — Settings infrastructure - **Story Points**: 2 (S) — Thread safety fix - **MoSCoW**: Could Have — Minor race condition, not blocking --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#7634
No description provided.