CVE-2026-34450
Description
The Claude SDK for Python provides access to the Claude API from Python applications. From version 0.86.0 to before version 0.87.0, the local filesystem memory tool in the Anthropic Python SDK created memory files with mode 0o666, leaving them world-readable on systems with a standard umask and world-writable in environments with a permissive umask such as many Docker base images. A local attacker on a shared host could read persisted agent state, and in containerized deployments could modify memory files to influence subsequent model behavior. Both the synchronous and asynchronous memory tool implementations were affected. This issue has been patched in version 0.87.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
anthropicPyPI | >= 0.86.0, < 0.87.0 | 0.87.0 |
Affected products
1- cpe:2.3:a:anthropic:claude_sdk_for_python:*:*:*:*:*:python:*:*Range: >=0.86.0,<0.87.0
Patches
1715030ceb4d6fix(memory): use restrictive file mode for memory files
1 file changed · +21 −12
src/anthropic/lib/tools/_beta_builtin_memory_tool.py+21 −12 modified@@ -42,6 +42,15 @@ MAX_LINES = 999999 LINE_NUMBER_WIDTH = len(str(MAX_LINES)) +# Owner read/write only. Avoids 0o666 which, in environments with a permissive +# umask (e.g. Docker where umask is often 0o000), would make memory files +# world-readable or even world-writable. +_FILE_CREATE_MODE = 0o600 +# The default mkdir mode is 0o777, but we want to be more restrictive for memory +# directories to avoid them being world-accessible in environments with permissive umasks +# (eg Docker) +_DIR_CREATE_MODE = 0o700 + class BetaAbstractMemoryTool(BetaBuiltinFunctionTool): """Abstract base class for memory tool implementations. @@ -275,7 +284,7 @@ def _atomic_write_file(target_path: Path, content: str) -> None: data = content.encode("utf-8") try: - fd = os.open(temp_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o666) + fd = os.open(temp_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, _FILE_CREATE_MODE) try: offset = 0 while offset < len(data): @@ -342,7 +351,7 @@ def __init__(self, base_path: str = "./memory"): super().__init__() self.base_path = Path(base_path) self.memory_root = self.base_path / "memories" - self.memory_root.mkdir(parents=True, exist_ok=True) + self.memory_root.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) def _validate_path(self, path: str) -> Path: """Validate and resolve memory paths""" @@ -434,10 +443,10 @@ def collect_items(dir_path: Path, relative_path: str, depth: int) -> None: def create(self, command: BetaMemoryTool20250818CreateCommand) -> str: full_path = self._validate_path(command.path) - full_path.parent.mkdir(parents=True, exist_ok=True) + full_path.parent.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) try: - fd = os.open(full_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o666) + fd = os.open(full_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, _FILE_CREATE_MODE) try: os.write(fd, command.file_text.encode("utf-8")) os.fsync(fd) @@ -549,7 +558,7 @@ def rename(self, command: BetaMemoryTool20250818RenameCommand) -> str: if new_full_path.exists(): raise ToolError(f"The destination {command.new_path} already exists") - new_full_path.parent.mkdir(parents=True, exist_ok=True) + new_full_path.parent.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) try: old_full_path.rename(new_full_path) @@ -563,7 +572,7 @@ def clear_all_memory(self) -> str: """Override the base implementation to provide file system clearing.""" if self.memory_root.exists(): shutil.rmtree(self.memory_root) - self.memory_root.mkdir(parents=True, exist_ok=True) + self.memory_root.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) return "All memory cleared" @@ -576,7 +585,7 @@ async def _async_atomic_write_file(target_path: AsyncPath, content: str) -> None try: def write_replace_and_sync() -> None: - fd = os.open(sync_temp_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o666) + fd = os.open(sync_temp_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, _FILE_CREATE_MODE) try: offset = 0 while offset < len(data): @@ -624,7 +633,7 @@ def __init__(self, base_path: str = "./memory"): async def _ensure_memory_root(self) -> None: """Ensure the memory root directory exists""" - await self.memory_root.mkdir(parents=True, exist_ok=True) + await self.memory_root.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) async def _validate_path(self, path: str) -> AsyncPath: """Validate and resolve memory paths""" @@ -724,13 +733,13 @@ async def create(self, command: BetaMemoryTool20250818CreateCommand) -> str: await self._ensure_memory_root() full_path = await self._validate_path(command.path) - await full_path.parent.mkdir(parents=True, exist_ok=True) + await full_path.parent.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) try: sync_full_path = Path(str(full_path)) def create_exclusive() -> None: - fd = os.open(sync_full_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o666) + fd = os.open(sync_full_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, _FILE_CREATE_MODE) try: os.write(fd, command.file_text.encode("utf-8")) os.fsync(fd) @@ -848,7 +857,7 @@ async def rename(self, command: BetaMemoryTool20250818RenameCommand) -> str: if await new_full_path.exists(): raise ToolError(f"The destination {command.new_path} already exists") - await new_full_path.parent.mkdir(parents=True, exist_ok=True) + await new_full_path.parent.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) try: await old_full_path.rename(new_full_path) @@ -862,5 +871,5 @@ async def clear_all_memory(self) -> str: """Override the base implementation to provide file system clearing.""" if await self.memory_root.exists(): await run_sync(shutil.rmtree, str(self.memory_root)) - await self.memory_root.mkdir(parents=True, exist_ok=True) + await self.memory_root.mkdir(parents=True, exist_ok=True, mode=_DIR_CREATE_MODE) return "All memory cleared"
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/anthropics/anthropic-sdk-python/commit/715030ceb4d6dd8d3546e999c680e29532bf1255nvdPatchWEB
- github.com/advisories/GHSA-q5f5-3gjm-7mfmghsaADVISORY
- github.com/anthropics/anthropic-sdk-python/security/advisories/GHSA-q5f5-3gjm-7mfmnvdVendor AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2026-34450ghsaADVISORY
- github.com/anthropics/anthropic-sdk-python/releases/tag/v0.87.0nvdRelease NotesWEB
News mentions
0No linked articles in our index yet.