CodeQL fixes (#763)

- Block SSRF in image cover proxy (validate URL scheme and reject
private IPs)
- Sanitize settings tab name to prevent path traversal
This commit is contained in:
Alex
2026-03-13 17:47:34 +00:00
committed by GitHub
parent ebf4312174
commit 0d856a3ef5
2 changed files with 37 additions and 1 deletions
+32
View File
@@ -1,12 +1,15 @@
"""Disk-based image cache with LRU eviction."""
import ipaddress
import json
import os
import socket
import threading
import time
from io import BytesIO
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
from urllib.parse import urlparse
import requests
@@ -466,6 +469,32 @@ class ImageCacheService:
'hit_rate': round(hit_rate, 1),
}
@staticmethod
def _is_safe_url(url: str) -> bool:
"""Check that a URL is safe to fetch (no SSRF to internal resources)."""
try:
parsed = urlparse(url)
except Exception:
return False
if parsed.scheme not in ('http', 'https'):
return False
hostname = parsed.hostname
if not hostname:
return False
try:
resolved = socket.getaddrinfo(hostname, None)
for _, _, _, _, sockaddr in resolved:
ip = ipaddress.ip_address(sockaddr[0])
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:
return False
except (socket.gaierror, ValueError):
return False
return True
def fetch_and_cache(self, cache_id: str, url: str) -> Optional[Tuple[bytes, str]]:
"""Fetch an image from URL and cache it.
@@ -477,6 +506,9 @@ class ImageCacheService:
Tuple of (image_data, content_type) or None on failure
"""
try:
if not self._is_safe_url(url):
logger.warning(f"Blocked request to disallowed URL: {url}")
return None
response = requests.get(
url,
+5 -1
View File
@@ -348,7 +348,11 @@ def _get_config_file_path(tab_name: str) -> Path:
# Core settings tabs share the main settings.json file
if tab_name in ("general", "search_mode"):
return config_dir / "settings.json"
return config_dir / "plugins" / f"{tab_name}.json"
# Sanitize tab_name to prevent path traversal
safe_name = Path(tab_name).name
if not safe_name or safe_name != tab_name:
raise ValueError(f"Invalid tab name: {tab_name}")
return config_dir / "plugins" / f"{safe_name}.json"
def _ensure_config_dir(tab_name: str) -> None: