fix: cloud mode path validation and sanitization (bmc-issue-103) (#332) · basicmachines-co/basic-memory@7616b2b · GitHub
Skip to content

Commit 7616b2b

Browse files
phernandezclaude
andauthored
fix: cloud mode path validation and sanitization (bmc-issue-103) (#332)
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 14c1fe4 commit 7616b2b

4 files changed

Lines changed: 175 additions & 6 deletions

File tree

src/basic_memory/api/routers/project_router.py

Lines changed: 1 addition & 0 deletions

src/basic_memory/services/project_service.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,30 @@ async def add_project(self, name: str, path: str, set_default: bool = False) ->
100100
ValueError: If the project already exists
101101
"""
102102
# in cloud mode, don't allow arbitrary paths.
103-
if config.cloud_mode:
103+
if self.config_manager.config.cloud_mode_enabled:
104104
basic_memory_home = os.getenv("BASIC_MEMORY_HOME")
105105
assert basic_memory_home is not None
106106
base_path = Path(basic_memory_home)
107107

108-
# Resolve to absolute path
109-
resolved_path = Path(os.path.abspath(os.path.expanduser(base_path / path))).as_posix()
108+
# Sanitize the input path for cloud mode
109+
# Strip leading slashes, home directory references, and parent directory references
110+
clean_path = path.lstrip("/").replace("~/", "").replace("~", "")
111+
112+
# Remove any parent directory traversal attempts
113+
path_parts = []
114+
for part in clean_path.split("/"):
115+
if part and part != "." and part != "..":
116+
path_parts.append(part)
117+
clean_path = "/".join(path_parts) if path_parts else ""
118+
119+
# Construct path relative to BASIC_MEMORY_HOME
120+
resolved_path = (base_path / clean_path).resolve().as_posix()
121+
122+
# Verify the resolved path is actually under BASIC_MEMORY_HOME
123+
if not resolved_path.startswith(base_path.resolve().as_posix()):
124+
raise ValueError(
125+
f"Cloud mode requires projects under {basic_memory_home}. Invalid path: {path}"
126+
)
110127
else:
111128
resolved_path = Path(os.path.abspath(os.path.expanduser(path))).as_posix()
112129

test-int/test_disable_permalinks_integration.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
"""Integration tests for the disable_permalinks configuration."""
22

33
import pytest
4-
from pathlib import Path
5-
from textwrap import dedent
64

75
from basic_memory.config import BasicMemoryConfig
86
from basic_memory.markdown import EntityParser, MarkdownProcessor
9-
from basic_memory.models import Project
107
from basic_memory.repository import (
118
EntityRepository,
129
ObservationRepository,

tests/services/test_project_service.py

Lines changed: 154 additions & 0 deletions

0 commit comments

Comments
 (0)