Skip to content

CPython 3.13: consolidated memory-safety and concurrency bugs #157196

Closed as not planned

Description

@Nievesjyl

Hello,

This issue consolidates 25 reproducible CPython 3.13 bugs involving memory safety and concurrency.

The bugs resulted from Python security research using static analysis. Each entry has a concrete PoC in the linked version-specific Gist. Although the collection is large, these bugs warrant inspection, especially the cases producing interpreter crashes, sanitizer failures, memory corruption, or similarly concrete failures.

This issue is associated with #157197 and #157198

Bugs

  1. asyncio Future callback registry race — Concurrent callback registration or removal can retire an unlocked callback-list item before remove_done_callback() promotes it, producing an ASan crash.
  2. Unlocked atexit callback array — Concurrent registry operations can use stale callback records and crash, while re-entrant comparison can delete an unrelated replacement callback.
  3. BaseException.__setstate__() shared-dictionary race — Concurrent value replacement can reclaim a dictionary entry between PyDict_Next() and reference promotion.
  4. Bytearray methods using unlocked shared storage — Concurrent storage replacement causes out-of-bounds reads and mixed-generation results across several bytearray operations.
  5. bytes() conversion of a shared list — The exact-list conversion path can promote an item reclaimed by concurrent clear or resize, producing an ASan crash.
  6. Shared CSV Reader state race — Concurrent next() calls can reallocate and corrupt the Reader's unlocked parser buffer and state.
  7. Shared CSV Writer record-buffer race — Concurrent writerow() calls can overwrite one another and emit a row containing mixed input generations.
  8. FrameLocalsProxy.__getitem__() extra-local race — Concurrent proxy assignment or deletion can reclaim a borrowed extra-local value before promotion.
  9. Writable live-frame fast-local race — Proxy replacement can free a fast-local value while the evaluator or PyFrame_GetVar() is acquiring it, causing impossible object state and allocator corruption.
  10. Function closure replacement during frame initialization — Concurrent closure replacement can release the tuple and cell while an unstarted frame initializes its free variables.
  11. Unsynchronized whole-interpreter PyConfig access — Concurrent configuration setters and readers produce heap-use-after-free failures in wide-string-list copying and conversion.
  12. Shared itertools combinator advancement — Concurrent next() calls corrupt mutable state in product, combinations, combinations_with_replacement, and permutations.
  13. Shared itertools.tee cache race — Concurrent advancement can expose an uninitialized shared-cache slot to Py_NewRef, crashing both same-branch and sibling-branch modes.
  14. Managed __dict__ replacement false miss — Attribute lookup can report AttributeError after inline storage is invalidated even though the replacement dictionary contains the attribute.
  15. OrderedDict borrowed-value promotion race — Fixed-key replacement can reclaim values consumed by setdefault(), copy(), or values iteration and corrupt the allocator.
  16. OrderedDict unlocked node state — Concurrent structural operations can invalidate the coupled base-dictionary table, fast-node array, and linked nodes during lookup.
  17. partial.__repr__() keyword-dictionary race — Fixed-key replacement can reclaim a borrowed keyword value before formatting promotes it.
  18. Exact-dictionary pickle batching race — Concurrent dictionary mutation can reclaim a borrowed entry before batch_dict_exact promotes it, producing an ASan crash.
  19. Exact-list pickle batching race — Concurrent list replacement or resize can reclaim an item before batch_list_exact promotes it.
  20. pickle.whichmodule() sys.modules race — Concurrent synthetic-module replacement can reclaim a borrowed module entry during the fallback scan and crash reference promotion.
  21. _PyConfig_FromDict() nested-list race — Concurrent mutation of warnoptions can retire a raw list item before its type check and conversion.
  22. globals["__builtins__"] replacement race — Evaluation can consume a borrowed builtins object after concurrent replacement frees it, causing stack or mutex corruption.
  23. SQLite converter-registry race — Concurrent public-registry replacement can finalize a borrowed converter before the cursor row-cast map owns it.
  24. str.maketrans() shared-dictionary race — Concurrent clear or replacement can retire borrowed keys and values, producing impossible translation tables or reclaimed objects.
  25. warnings.filters list race — Direct list mutation can finalize a borrowed filter tuple before get_filter() inspects and promotes it, producing an ASan crash.

Activity

  1. gvanrossum commented on Sep 8, 2026

    @gvanrossum
    Member

    Thank you! That looks like the result of some serious research.

    Is there any chance we can convince you to redo your analysis with 3.15 rc2 (which is expected to be virtually identical to the final 3.15.0 release)? And again in free-threading mode, which increases the opportunity for concurrency bugs. Even if we decide not to rush any fixes in 3.15.0, we could fix any of these in follow-up bugfix releases, and backport them as well to 3.14 and 3.13.

    In terms of security, I think these are not attack vectors per se. It looks as if they can't be triggered by sending malicious data, but require being able to run Python code; and once an attacker has that ability, they can already do anything that the user they impersonate is allowed to do. Causing a crash of the Python interpreter itself is trivial (os.kill(os.getpid(), 9)). (But don't trust me on this; a member of Python's security team should

    In order to prioritize these, we'd have to look at the likelihood that a user just doing their thing would accidentally trigger one of these.

  2. StanFromIreland commented on Sep 8, 2026

    @StanFromIreland
    Member

    Regarding security, please review possible vulnerabilities against our Security Policy, and submit them if necessary (more information on how to do this is provided in the policy). But from a quick glance I concur with Gudio, they all seem to require executing arbitrary in-process Python code.

  3. Nievesjyl commented on Sep 8, 2026

    @Nievesjyl
    Author

    Thank you for your response.

    I would like to clarify the main concern behind these reports. Regardless of whether these cases ultimately constitute practical attack vectors, ordinary Python-level code should not cause the interpreter itself to crash, corrupt memory, or otherwise fail at the native level.

    These cases use ordinary Python operations and public Python APIs, without directly manipulating native memory. Therefore, even if some of them involve complex or concurrent execution patterns, the fact that they can trigger native crashes or memory-safety violations in CPython indicates implementation-level issues that are worth further investigation.

    The purpose of these reports is not to claim that every case is necessarily security-exploitable, but rather to identify cases where ordinary Python code can compromise the interpreter's internal stability or memory safety.

    In addition, we have tested Python 3.14 and 3.15 as well, and we are currently organizing the corresponding submission materials. We plan to open separate issues for the 3.14 and 3.15 cases. The issues for 3.13, 3.14, and 3.15 will reference each other, and I will also provide a file documenting the issues that are reproducible across all three versions.

    I will @mention you in the follow-up issues. If possible, I would appreciate it if you could evaluate this set of issues together with the security team.

    Thank you!

  4. gvanrossum commented on Sep 8, 2026

    @gvanrossum
    Member

    Sorry, it is up to the security team now. I no longer review PRs, as a general rule.

  5. Nievesjyl commented on Sep 11, 2026

    @Nievesjyl
    Author

    We are preparing a carefully screened report that complies with CPython policy, so we are closing this issue.

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

    extension-modulesC modules in the Modules dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions