{"id":"PYSEC-2026-2479","summary":"FlaskBB: SSRF in get_image_info() via unrestricted avatar URL","details":"###Summary\nA Server-Side Request Forgery (SSRF) vulnerability in get_image_info() allows any authenticated user to force the server to send HTTP requests to arbitrary internal endpoints, including cloud metadata services (e.g., AWS 169.254.169.254). This is a blind SSRF with confirmed internal port scanning and internal API triggering capabilities. CVSS 6.5 Medium.\n\n###Details\nIn flaskbb/utils/helpers.py (line 571), the url parameter is passed directly to requests.get(url, stream=True) without any validation of scheme, host, or IP address.\n```\npython# flaskbb/utils/helpers.py:571\ndef get_image_info(url: str):\n    r = requests.get(url, timeout=(3.05, 27), stream=True)\n```\n\nAttack chain:\n\n```\nPOST /user/settings/user-details (avatar URL)\n→ ValidateAvatarURL.validate()    # validators.py:103\n→ check_image(avatar)             # helpers.py:628\n→ get_image_info(url)             # helpers.py:571\n→ requests.get(url)               # No domain/IP restriction\nEntry points:\n\n/user/settings/user-details (any authenticated user)\n/admin/users/\u003cid\u003e/edit (admin only)\n\n```\n\n###PoC\n[submit.zip](https://github.com/user-attachments/files/26301527/submit.zip)\n\nLog in to FlaskBB as any user\nNavigate to Settings → User Details\nEnter http://169.254.169.254/latest/meta-data/ as the avatar URL\nSubmit the form\nThe server sends a GET request to the internal metadata endpoint\n\nThree exploitation channels confirmed:\n\nServer-side request: Captured on mock metadata server\nInternal port scan: check_image() returns distinct errors (CONN_REFUSED, NO_CONTENT_LENGTH, TYPE_NOT_ALLOWED, SUCCESS) that map internal network topology\nInternal API triggering: Mock APIs on 127.0.0.1:9200 triggered via SSRF (deploy, shutdown, key dump endpoints)\n\n###Impact\nAny authenticated user is impacted. Attackers can force the server to request internal services, cloud metadata endpoints, or private network resources. On cloud deployments (AWS/GCP/Azure), IAM credentials can be leaked. In production, any GET-triggered internal service is reachable: CI/CD webhooks, Elasticsearch, etcd, Consul, etc.","aliases":["CVE-2026-46556","GHSA-xq32-9g7q-7297"],"modified":"2026-07-13T16:31:46.478606305Z","published":"2026-07-13T15:19:10.820662Z","references":[{"type":"WEB","url":"https://github.com/flaskbb/flaskbb/security/advisories/GHSA-xq32-9g7q-7297"},{"type":"PACKAGE","url":"https://github.com/flaskbb/flaskbb"},{"type":"PACKAGE","url":"https://pypi.org/project/flaskbb"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-xq32-9g7q-7297"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46556"}],"affected":[{"package":{"name":"flaskbb","ecosystem":"PyPI","purl":"pkg:pypi/flaskbb"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.2.0"}]}],"versions":["2.0.0","2.0.0.dev0","2.0.1","2.0.2","2.2.0"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/flaskbb/PYSEC-2026-2479.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"}]}