mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 17:47:06 +08:00
fix: prevent path traversal in backup importer (CWE-22) (#7681)
* fix: prevent path traversal in backup importer (CWE-22) Validate that all file write targets resolve within their expected base directories before writing. This prevents crafted backup ZIP files from writing to arbitrary filesystem locations via malicious path values in attachment records, media file paths, or directory entries. * fix: use Path.is_relative_to for robust path containment check * fix: add explicit strict=False to Path.resolve() calls * style: format backup importer --------- Co-authored-by: 邹永赫 <1259085392@qq.com>
This commit is contained in:
@@ -59,6 +59,20 @@ def _get_major_version(version_str: str) -> str:
|
||||
return "0.0"
|
||||
|
||||
|
||||
def _validate_path_within(target_path: Path, base_dir: Path) -> bool:
|
||||
"""Validate that target_path is within base_dir after resolving symlinks.
|
||||
|
||||
Prevents path traversal attacks (CWE-22) by ensuring the resolved
|
||||
target path is relative to the resolved base directory.
|
||||
"""
|
||||
try:
|
||||
resolved = target_path.resolve(strict=False)
|
||||
base_resolved = base_dir.resolve(strict=False)
|
||||
return resolved.is_relative_to(base_resolved)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
|
||||
|
||||
CMD_CONFIG_FILE_PATH = os.path.join(get_astrbot_data_path(), "cmd_config.json")
|
||||
KB_PATH = get_astrbot_knowledge_base_path()
|
||||
DEFAULT_PLATFORM_STATS_INVALID_COUNT_WARN_LIMIT = 5
|
||||
@@ -765,6 +779,10 @@ class AstrBotImporter:
|
||||
try:
|
||||
rel_path = name[len(media_prefix) :]
|
||||
target_path = kb_dir / rel_path
|
||||
# Validate path is within kb directory (CWE-22)
|
||||
if not _validate_path_within(target_path, kb_dir):
|
||||
logger.warning(f"媒体文件路径越界,已跳过: {target_path}")
|
||||
continue
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zf.open(name) as src, open(target_path, "wb") as dst:
|
||||
dst.write(src.read())
|
||||
@@ -827,6 +845,11 @@ class AstrBotImporter:
|
||||
else:
|
||||
target_path = attachments_dir / os.path.basename(name)
|
||||
|
||||
# Validate path is within attachments directory (CWE-22)
|
||||
if not _validate_path_within(target_path, attachments_dir):
|
||||
logger.warning(f"附件路径越界,已跳过: {target_path}")
|
||||
continue
|
||||
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zf.open(name) as src, open(target_path, "wb") as dst:
|
||||
dst.write(src.read())
|
||||
@@ -904,6 +927,10 @@ class AstrBotImporter:
|
||||
continue
|
||||
|
||||
target_path = target_dir / rel_path
|
||||
# Validate path is within target directory (CWE-22)
|
||||
if not _validate_path_within(target_path, target_dir):
|
||||
result.add_warning(f"文件路径越界,已跳过: {name}")
|
||||
continue
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with zf.open(name) as src, open(target_path, "wb") as dst:
|
||||
|
||||
Reference in New Issue
Block a user