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>
This commit is contained in:
Paul Hernandez
2025-10-04 22:10:21 -05:00
committed by GitHub
parent 14c1fe4e89
commit 7616b2bb08
4 changed files with 175 additions and 6 deletions
@@ -194,6 +194,7 @@ async def add_project(
Response confirming the project was added
"""
try: # pragma: no cover
# The service layer now handles cloud mode validation and path sanitization
await project_service.add_project(
project_data.name, project_data.path, set_default=project_data.set_default
)
+20 -3
View File
@@ -100,13 +100,30 @@ class ProjectService:
ValueError: If the project already exists
"""
# in cloud mode, don't allow arbitrary paths.
if config.cloud_mode:
if self.config_manager.config.cloud_mode_enabled:
basic_memory_home = os.getenv("BASIC_MEMORY_HOME")
assert basic_memory_home is not None
base_path = Path(basic_memory_home)
# Resolve to absolute path
resolved_path = Path(os.path.abspath(os.path.expanduser(base_path / path))).as_posix()
# Sanitize the input path for cloud mode
# Strip leading slashes, home directory references, and parent directory references
clean_path = path.lstrip("/").replace("~/", "").replace("~", "")
# Remove any parent directory traversal attempts
path_parts = []
for part in clean_path.split("/"):
if part and part != "." and part != "..":
path_parts.append(part)
clean_path = "/".join(path_parts) if path_parts else ""
# Construct path relative to BASIC_MEMORY_HOME
resolved_path = (base_path / clean_path).resolve().as_posix()
# Verify the resolved path is actually under BASIC_MEMORY_HOME
if not resolved_path.startswith(base_path.resolve().as_posix()):
raise ValueError(
f"Cloud mode requires projects under {basic_memory_home}. Invalid path: {path}"
)
else:
resolved_path = Path(os.path.abspath(os.path.expanduser(path))).as_posix()