Summary
InMemorySessionStore joins key components with / without escaping them, so distinct SessionKey values can map to the same dictionary key.
Affected code
src/claude_agent_sdk/_internal/session_store.py:27-32, 64-129
Current behavior
_key_to_string() creates:
"/".join([project_key, session_id, optional_subpath])
No component is escaped or constrained. For example:
{"project_key": "a/b", "session_id": "c"}
{"project_key": "a", "session_id": "b", "subpath": "c"}
both become a/b/c.
The implementation also uses string-prefix parsing for list_sessions(), cascading delete(), list_subkeys(), and size, so delimiter ambiguity affects more than direct load/append.
Why this matters
Distinct logical sessions or tenants can mix entries, appear under the wrong listing, or be deleted together. Although this adapter is documented for testing and development, it is the shipped reference implementation and is used to validate SessionStore behavior.
Tests built on the reference adapter can also pass while exercising a different logical key than intended.
Expected behavior
SessionKey components should remain structurally distinct regardless of their text contents.
Possible fix
Use tuple keys internally, for example:
(project_key, session_id, subpath_or_none)
Listing and cascade operations can then compare tuple fields instead of parsing prefixes. Add adversarial tests containing / in project keys and subpaths, including cases that collide under the current encoding.
Environment
- Repository revision: current
main audit at SDK version 0.2.128
- Bundled CLI version: 2.1.220
- Python test suite: 1,291 passed, 5 skipped
- Ruff and mypy: clean
I searched the existing issues and pull requests using the affected symbols and behavior before filing this.
Summary
InMemorySessionStorejoins key components with/without escaping them, so distinctSessionKeyvalues can map to the same dictionary key.Affected code
src/claude_agent_sdk/_internal/session_store.py:27-32, 64-129Current behavior
_key_to_string()creates:No component is escaped or constrained. For example:
{"project_key": "a/b", "session_id": "c"}{"project_key": "a", "session_id": "b", "subpath": "c"}both become
a/b/c.The implementation also uses string-prefix parsing for
list_sessions(), cascadingdelete(),list_subkeys(), andsize, so delimiter ambiguity affects more than direct load/append.Why this matters
Distinct logical sessions or tenants can mix entries, appear under the wrong listing, or be deleted together. Although this adapter is documented for testing and development, it is the shipped reference implementation and is used to validate SessionStore behavior.
Tests built on the reference adapter can also pass while exercising a different logical key than intended.
Expected behavior
SessionKey components should remain structurally distinct regardless of their text contents.
Possible fix
Use tuple keys internally, for example:
Listing and cascade operations can then compare tuple fields instead of parsing prefixes. Add adversarial tests containing
/in project keys and subpaths, including cases that collide under the current encoding.Environment
mainaudit at SDK version 0.2.128I searched the existing issues and pull requests using the affected symbols and behavior before filing this.