Security audit: fix IDOR, add rate limiting, HMAC auth, token hashing, XSS sanitization
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m22s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m22s
Critical: Add ownership checks to all order routes (IDOR fix). High: Redis rate limiting on auth endpoints, HMAC-signed internal service calls replacing header-presence-only checks, nh3 HTML sanitization on ghost_sync and product import, internal auth on market API endpoints, SHA-256 hashed OAuth grant/code tokens. Medium: SECRET_KEY production guard, AP signature enforcement, is_admin param removal, cart_sid validation, SSRF protection on remote actor fetch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,8 +29,43 @@ AP_CONTENT_TYPE = "application/activity+json"
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _is_safe_url(url: str) -> bool:
|
||||
"""Reject URLs pointing to private/internal IPs to prevent SSRF."""
|
||||
from urllib.parse import urlparse
|
||||
import ipaddress
|
||||
|
||||
parsed = urlparse(url)
|
||||
|
||||
# Require HTTPS
|
||||
if parsed.scheme != "https":
|
||||
return False
|
||||
|
||||
hostname = parsed.hostname
|
||||
if not hostname:
|
||||
return False
|
||||
|
||||
# Block obvious internal hostnames
|
||||
if hostname in ("localhost", "127.0.0.1", "::1", "0.0.0.0"):
|
||||
return False
|
||||
|
||||
try:
|
||||
addr = ipaddress.ip_address(hostname)
|
||||
if addr.is_private or addr.is_loopback or addr.is_reserved or addr.is_link_local:
|
||||
return False
|
||||
except ValueError:
|
||||
# Not an IP literal — hostname is fine (DNS resolution handled by httpx)
|
||||
# Block common internal DNS patterns
|
||||
if hostname.endswith(".internal") or hostname.endswith(".local"):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def fetch_remote_actor(actor_url: str) -> dict | None:
|
||||
"""Fetch a remote actor's JSON-LD profile."""
|
||||
if not _is_safe_url(actor_url):
|
||||
log.warning("Blocked SSRF attempt: %s", actor_url)
|
||||
return None
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
resp = await client.get(
|
||||
|
||||
Reference in New Issue
Block a user