Merge commit from fork
* SSRF Patch * Delete .claude/settings.local.json * Delete docker-compose.override.yml --------- Co-authored-by: JDLotWire <jonah.dacosta@lotwire.ca> Co-authored-by: taylor_socfortress <111797488+taylorwalton@users.noreply.github.com>
Jonah DaCosta committed
Apr 24, 2026 at 11:03 UTC
7152f9e4aef869ffbd28aa4c3d982687ce735c31
2 files changed
+17
backend/app/connectors/wazuh_indexer/routes/sigma.py
+3
@@ -6,10 +6,12 @@ from fastapi import Depends
6
from fastapi import File
7
from fastapi import HTTPException
8
from fastapi import Query
9
+from fastapi import Security
10
from fastapi import UploadFile
11
from loguru import logger
12
from sqlalchemy.ext.asyncio import AsyncSession
13
14
+from app.auth.utils import AuthHandler
15
from app.connectors.wazuh_indexer.schema.sigma import ActivateSigmaQueryResponse
16
from app.connectors.wazuh_indexer.schema.sigma import BulkUploadToDBResponse
17
from app.connectors.wazuh_indexer.schema.sigma import CreateSigmaQuery
@@ -183,6 +185,7 @@ async def create_sigma_query_endpoint(
185
186
@wazuh_indexer_sigma_router.post(
187
"/download",
188
+ dependencies=[Security(AuthHandler().get_current_user)],
189
)
190
async def download_sigma_queries_endpoint(
191
request: DownloadSigmaRulesRequest,
backend/app/connectors/wazuh_indexer/services/sigma/sigma_download.py
+14
@@ -1,11 +1,16 @@
1
import os
2
import shutil
3
import zipfile
4
+from pathlib import Path
5
from typing import List
6
+from urllib.parse import urlparse
7
8
import requests
9
+from fastapi import HTTPException
10
from loguru import logger
11
12
+ALLOWED_HOSTS = {"github.com", "raw.githubusercontent.com"}
13
+
14
15
async def download_and_extract_zip(url: str) -> None:
16
"""
@@ -26,6 +31,10 @@ async def download_and_extract_zip(url: str) -> None:
31
os.makedirs(full_path, exist_ok=True)
32
33
# Download the zipped folder
34
+ parsed_url = urlparse(url)
35
+ if parsed_url.hostname not in ALLOWED_HOSTS:
36
+ raise HTTPException(status_code=400, detail="Only approved Sigma download hosts are allowed.")
37
+
38
response = requests.get(url)
39
response.raise_for_status() # Check if the request was successful
40
@@ -35,6 +44,11 @@ async def download_and_extract_zip(url: str) -> None:
44
45
# Extract the contents of the zipped folder
46
with zipfile.ZipFile(local_zip_path, "r") as zip_ref:
47
+ extract_root = Path(full_path).resolve()
48
+ for member_name in zip_ref.namelist():
49
+ dest = (Path(full_path) / member_name).resolve()
50
+ if not str(dest).startswith(str(extract_root)):
51
+ raise ValueError(f"Zip Slip attempt blocked: {member_name}")
52
zip_ref.extractall(full_path)
53
54
# Remove the downloaded zip file