Spaces:
Running
Running
Download security_utils.py from mrfaraidun/auravision-api: direct link, hf CLI and curl.
- Browser
- Download file 3.19 kB
-
https://huggingface.co/spaces/mrfaraidun/auravision-api/resolve/main/security_utils.py
- Command line
-
hf download hf://spaces/mrfaraidun/auravision-api/security_utils.py
-
curl -L -o security_utils.py https://huggingface.co/spaces/mrfaraidun/auravision-api/resolve/main/security_utils.py
3.19 kB
| import os | |
| import re | |
| import socket | |
| import urllib.parse | |
| import ipaddress | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| # Allowed domains for visual asset queries | |
| ALLOWED_DOMAINS = { | |
| "image.pollinations.ai", | |
| "pollinations.ai", | |
| } | |
| def sanitize_filename(filename: str) -> str: | |
| """ | |
| Sanitizes a filename to prevent path traversal and arbitrary writes. | |
| Only allows alphanumeric characters, dots, dashes, and underscores. | |
| """ | |
| # Extract basename to strip out path separators | |
| base = os.path.basename(filename) | |
| # Strip any leading dots or whitespace | |
| base = base.lstrip(". \t") | |
| # Remove characters that are not alphanumeric, dot, dash, or underscore | |
| sanitized = re.sub(r"[^a-zA-Z0-9_\.-]", "_", base) | |
| # Restrict length to prevent filesystem errors | |
| if len(sanitized) > 255: | |
| parts = sanitized.rsplit(".", 1) | |
| if len(parts) == 2: | |
| name, ext = parts | |
| sanitized = name[:255-len(ext)-1] + "." + ext | |
| else: | |
| sanitized = sanitized[:255] | |
| # Fallback to default if completely cleaned out | |
| if not sanitized or sanitized in (".", ".."): | |
| sanitized = "uploaded_file" | |
| return sanitized | |
| def is_safe_ip(ip_str: str) -> bool: | |
| """ | |
| Checks if an IP address is a public, non-loopback, and non-private IP. | |
| """ | |
| try: | |
| ip = ipaddress.ip_address(ip_str) | |
| # Block private, loopback, link-local, multicast, reserved, unspecified | |
| if (ip.is_private or | |
| ip.is_loopback or | |
| ip.is_link_local or | |
| ip.is_multicast or | |
| ip.is_reserved or | |
| ip.is_unspecified): | |
| return False | |
| return True | |
| except ValueError: | |
| return False | |
| def is_safe_url(url: str) -> bool: | |
| """ | |
| Verifies that the URL points to a safe destination (mitigating SSRF). | |
| Resolves the domain and confirms it maps to a public IP range. | |
| """ | |
| try: | |
| parsed = urllib.parse.urlparse(url) | |
| # Enforce HTTP/HTTPS schemes | |
| if parsed.scheme not in ("http", "https"): | |
| logger.warning(f"Rejected insecure URL scheme: {parsed.scheme}") | |
| return False | |
| hostname = parsed.hostname | |
| if not hostname: | |
| return False | |
| # Restrict domain list to known external image resources if possible | |
| # Since Pollinations AI is used, check if it fits whitelist or falls back to IP check | |
| # For flexibility, we allow any public IP destination but log warning if not in whitelist | |
| if hostname not in ALLOWED_DOMAINS: | |
| logger.info(f"Accessing external domain outside whitelist: {hostname}") | |
| # Resolve hostname to IP addresses | |
| ips = socket.getaddrinfo(hostname, None) | |
| for family, _, _, _, sockaddr in ips: | |
| ip = sockaddr[0] | |
| if not is_safe_ip(ip): | |
| logger.warning(f"SSRF Check: Hostname {hostname} resolved to unsafe IP {ip}") | |
| return False | |
| return True | |
| except Exception as e: | |
| logger.error(f"URL security check failed: {e}") | |
| return False | |