mirror of
https://github.com/Av0idD4rk/firegex.git
synced 2026-10-23 15:30:59 +00:00
CRITICAL: fix possible path traversal
This commit is contained in:
parent
16f96aa6f6
commit
16d0bfd169
@ -6,13 +6,14 @@ import psutil
|
||||
import sys
|
||||
import nftables
|
||||
from socketio import AsyncServer
|
||||
from fastapi import Path
|
||||
from typing import Annotated
|
||||
from typing import Annotated, List, Union
|
||||
from functools import wraps
|
||||
from pydantic import BaseModel, ValidationError
|
||||
from pydantic import BaseModel, ValidationError, Field
|
||||
import traceback
|
||||
from utils.models import StatusMessageModel
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
LOCALHOST_IP = socket.gethostbyname(os.getenv("LOCALHOST_IP","127.0.0.1"))
|
||||
|
||||
@ -31,7 +32,32 @@ FIREGEX_SOCKET = os.path.join(FIREGEX_SOCKET_DIR, "firegex.sock") if FIREGEX_SOC
|
||||
JWT_ALGORITHM: str = "HS256"
|
||||
API_VERSION = "{{VERSION_PLACEHOLDER}}" if "{" not in "{{VERSION_PLACEHOLDER}}" else "0.0.0"
|
||||
|
||||
PortType = Annotated[int, Path(gt=0, lt=65536)]
|
||||
PortType = Annotated[int, Field(gt=0, lt=65536)]
|
||||
|
||||
def safe_join(base_dir: Union[str, Path], *paths: str) -> Path:
|
||||
"""
|
||||
Safely join a base directory with one or more path components.
|
||||
|
||||
Returns the resolved Path object if safe.
|
||||
Raises HTTPException 403 if a directory traversal attack is detected.
|
||||
"""
|
||||
# 1. Convert base_dir to a resolved, absolute Path
|
||||
base_path = Path(base_dir).resolve()
|
||||
|
||||
# 2. Join the parts and resolve the result (removes symbols like '../')
|
||||
# If the user input is an absolute path (starting with /),
|
||||
# joinpath handles it correctly or we can strip leading slashes.
|
||||
clean_paths = [p.lstrip("/") for p in paths]
|
||||
target_path = base_path.joinpath(*clean_paths).resolve()
|
||||
|
||||
# 3. Security check
|
||||
if not target_path.is_relative_to(base_path):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Access denied: Path is invalid."
|
||||
)
|
||||
|
||||
return target_path
|
||||
|
||||
async def run_func(func, *args, **kwargs):
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
|
||||
@ -5,7 +5,7 @@ from typing import Callable
|
||||
from fastapi import APIRouter
|
||||
from starlette.responses import StreamingResponse
|
||||
from fastapi.responses import FileResponse
|
||||
from utils import DEBUG, ON_DOCKER, ROUTERS_DIR, list_files, run_func
|
||||
from utils import DEBUG, ON_DOCKER, ROUTERS_DIR, list_files, run_func, safe_join
|
||||
from utils.models import ResetRequest
|
||||
import asyncio
|
||||
import traceback
|
||||
@ -20,7 +20,7 @@ async def frontend_debug_proxy(path):
|
||||
return StreamingResponse(resp.aiter_bytes(),status_code=resp.status_code, headers=resp.headers)
|
||||
|
||||
async def react_deploy(path):
|
||||
file_request = os.path.join(REACT_BUILD_DIR, path)
|
||||
file_request = safe_join(REACT_BUILD_DIR, path)
|
||||
if not os.path.isfile(file_request):
|
||||
return FileResponse(REACT_HTML_PATH, media_type='text/html')
|
||||
else:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user