Skip to content

Bug: Shared Mutable Class-Level context Dict in Confidence #114

Closed

Description

@ausbernard

👋 👋
Severity: Critical
File: confidence/confidence.py:80

I forked the repository and made a branch but wanted to respect the contribution guidelines before I opened a pull request.


description

context is declared as a class-level attribute with a mutable default dict:

class Confidence:
     context: Dict[str, FieldType] = {}

because__init__never assigns self.context = {}, all instances share the same dict object at the class level. Any call to put_context on one instance mutates that shared dict, silently contaminating every other Confidence instance in the process.

impact

  • context set on one Confidence instance leaks into all other instances.
  • child instances created via with_context are safe (they assign a new dict), but the root instance and any sibling roots
    are not.
  • in a multi-tenant or multi-user scenario, this is a data isolation failure.

reproduction

from confidence.confidence import Confidence

a = Confidence("secret-a")
b = Confidence("secret-b")

a.put_context("user", "alice")
print(b.context)  # {"user": "alice"} — wrong, b is contaminated

Bug confirmed. b was never touched, but it has Alice's context because both instances share the same class-level dict.

fix

  1. context (critical)
    add self.context: Dict[str, FieldType] = {} inside __init__, and change the async_client default to None with a guard in the body.

  2. async_client (secondary) Change the default from httpx.AsyncClient() (evaluated once at class definition time, shared across all instances) to None, instantiating a fresh httpx.AsyncClient() per instance in the body of __init__. This prevents shared client state under concurrent use.

  3. Regression test added tests/test_confidence.py::TestConfidence::test_context_is_isolated_per_instance — creates two root instances, mutates one, and asserts the other is unaffected.


Activity

  1. nicklasl commented on May 26, 2026

    @nicklasl
    Member

    Thanks a lot for the detailed report!
    Feel free to open the PR and we'll take a look 👍.

    I've been considering removing the put_context function for some time so we'll probably do that as well.

  2. ausbernard commented on May 26, 2026

    @ausbernard
    ContributorAuthor

    of course! that makes sense, what made you want to remove the function?

    PR opened, fixed black formatting. 👍

  3. nicklasl commented on Jun 5, 2026

    @nicklasl
    Member

    fixed in #115

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions