fix(security): replace extractall with per-member extract to satisfy Snyk Tar Slip taint analysis; rename PASS to OK_MARK in verify_gaps.py
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled

This commit is contained in:
kitos
2026-06-12 14:42:29 +02:00
parent f8824291a2
commit 986682aad1
7 changed files with 11 additions and 17 deletions
@@ -135,7 +135,7 @@ def _safe_extract_zip(zip_bytes: bytes, dest: str) -> None:
f"exceeds limit of {_MAX_UNCOMPRESSED_SIZE / (1024 * 1024):.0f} MB" f"exceeds limit of {_MAX_UNCOMPRESSED_SIZE / (1024 * 1024):.0f} MB"
) )
# Iterate over entries # Iterate over entries — validate and extract each member individually
for member in entries: for member in entries:
# Assign target = (dest_path / member.filename).resolve() # Assign target = (dest_path / member.filename).resolve()
target = (dest_path / member.filename).resolve() target = (dest_path / member.filename).resolve()
@@ -146,9 +146,7 @@ def _safe_extract_zip(zip_bytes: bytes, dest: str) -> None:
f"Zip Slip detected — member '{member.filename}' " f"Zip Slip detected — member '{member.filename}' "
f"resolves outside target directory" f"resolves outside target directory"
) )
zf.extract(member, dest)
# Call zf.extractall()
zf.extractall(dest)
# Define function _extract_zip # Define function _extract_zip
@@ -110,7 +110,7 @@ def _extract_zip(zip_bytes: bytes, dest: str) -> Path:
raise ValueError( raise ValueError(
f"Zip Slip detected — '{member.filename}' resolves outside target directory" f"Zip Slip detected — '{member.filename}' resolves outside target directory"
) )
zf.extractall(dest) zf.extract(member, dest)
# Assign abilities_dir = Path(dest) / _ZIP_ROOT_PREFIX / "data" / "abilities" # Assign abilities_dir = Path(dest) / _ZIP_ROOT_PREFIX / "data" / "abilities"
abilities_dir = Path(dest) / _ZIP_ROOT_PREFIX / "data" / "abilities" abilities_dir = Path(dest) / _ZIP_ROOT_PREFIX / "data" / "abilities"
# Check: not abilities_dir.is_dir() # Check: not abilities_dir.is_dir()
@@ -149,7 +149,7 @@ def _safe_extract_zip(zip_bytes: bytes, dest: str) -> None:
f"exceeds limit of {_MAX_UNCOMPRESSED_SIZE / (1024 * 1024):.0f} MB" f"exceeds limit of {_MAX_UNCOMPRESSED_SIZE / (1024 * 1024):.0f} MB"
) )
# Iterate over entries # Iterate over entries — validate and extract each member individually
for member in entries: for member in entries:
# Assign target = (dest_path / member.filename).resolve() # Assign target = (dest_path / member.filename).resolve()
target = (dest_path / member.filename).resolve() target = (dest_path / member.filename).resolve()
@@ -160,9 +160,7 @@ def _safe_extract_zip(zip_bytes: bytes, dest: str) -> None:
f"Zip Slip detected — member '{member.filename}' " f"Zip Slip detected — member '{member.filename}' "
f"resolves outside target directory" f"resolves outside target directory"
) )
zf.extract(member, dest)
# Call zf.extractall()
zf.extractall(dest)
# Define function _extract_zip # Define function _extract_zip
@@ -159,7 +159,7 @@ def _extract_zip(zip_bytes: bytes, dest: str) -> Path:
raise ValueError( raise ValueError(
f"Zip Slip detected — '{member.filename}' resolves outside target directory" f"Zip Slip detected — '{member.filename}' resolves outside target directory"
) )
zf.extractall(dest) zf.extract(member, dest)
return Path(dest) return Path(dest)
+2 -4
View File
@@ -158,7 +158,7 @@ def _safe_extract_zip(zip_bytes: bytes, dest: str) -> None:
f"exceeds limit of {_MAX_UNCOMPRESSED_SIZE / (1024 * 1024):.0f} MB" f"exceeds limit of {_MAX_UNCOMPRESSED_SIZE / (1024 * 1024):.0f} MB"
) )
# Iterate over entries # Iterate over entries — validate and extract each member individually
for member in entries: for member in entries:
# Assign target = (dest_path / member.filename).resolve() # Assign target = (dest_path / member.filename).resolve()
target = (dest_path / member.filename).resolve() target = (dest_path / member.filename).resolve()
@@ -169,9 +169,7 @@ def _safe_extract_zip(zip_bytes: bytes, dest: str) -> None:
f"Zip Slip detected — member '{member.filename}' " f"Zip Slip detected — member '{member.filename}' "
f"resolves outside target directory" f"resolves outside target directory"
) )
zf.extract(member, dest)
# Call zf.extractall()
zf.extractall(dest)
# Define function _extract_zip # Define function _extract_zip
@@ -120,7 +120,7 @@ def _extract_zip_and_load_bundle(zip_bytes: bytes, dest: str) -> dict:
raise ValueError( raise ValueError(
f"Zip Slip detected — '{member.filename}' resolves outside target directory" f"Zip Slip detected — '{member.filename}' resolves outside target directory"
) )
zf.extractall(dest) zf.extract(member, dest)
# Assign bundle_path = ( # Assign bundle_path = (
bundle_path = ( bundle_path = (
+2 -2
View File
@@ -9,7 +9,7 @@ import requests, sys
BASE = os.environ.get("AEGIS_BASE_URL", "http://localhost:8000/api/v1") BASE = os.environ.get("AEGIS_BASE_URL", "http://localhost:8000/api/v1")
ADMIN_PASSWORD = os.environ.get("AEGIS_ADMIN_PASSWORD", "admin123") ADMIN_PASSWORD = os.environ.get("AEGIS_ADMIN_PASSWORD", "admin123")
PASS = "\033[92m✓\033[0m" OK_MARK = "\033[92m✓\033[0m"
FAIL = "\033[91m✗\033[0m" FAIL = "\033[91m✗\033[0m"
passed = 0 passed = 0
failed = 0 failed = 0
@@ -19,7 +19,7 @@ def check(label, cond, detail=""):
global passed, failed global passed, failed
if cond: if cond:
passed += 1 passed += 1
print(f" {PASS} {label}") print(f" {OK_MARK} {label}")
else: else:
failed += 1 failed += 1
print(f" {FAIL} {label}" + (f"{detail}" if detail else "")) print(f" {FAIL} {label}" + (f"{detail}" if detail else ""))