Indico has Server-Side Request Forgery (SSRF) in multiple places
Description
Indico is an event management system that uses Flask-Multipass, a multi-backend authentication system for Flask. Versions prior to 3.3.10 are vulnerable to server-side request forgery. Indico makes outgoing requests to user-provides URLs in various places. This is mostly intentional and part of Indico's functionality but is never intended to let users access "special" targets such as localhost or cloud metadata endpoints. Users should upgrade to version 3.3.10 to receive a patch. Those who do not have IPs that expose sensitive data without authentication (typically because they do not host Indico on AWS) are not affected. Only event organizers can access endpoints where SSRF could be used to actually see the data returned by such a request. For those who trust their event organizers, the risk is also very limited. For additional security, both before and after patching, one may also use the common proxy-related environment variables (in particular http_proxy and https_proxy) to force outgoing requests to go through a proxy that limits requests in whatever way you deem useful/necessary. These environment variables would need to be set both on the indico-uwsgi and indico-celery services.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
indicoPyPI | < 3.3.10 | 3.3.10 |
Affected products
1Patches
170d341826116Protect against SSRF via DNS rebinding (#7283)
2 files changed · +35 −1
indico/__init__.py+2 −0 modified@@ -6,9 +6,11 @@ # LICENSE file for more details. from indico.util.mimetypes import register_custom_mimetypes +from indico.util.network import patch_socket_getaddrinfo __version__ = '3.3.10-dev' PREFERRED_PYTHON_VERSION_SPEC = '~=3.12.2' register_custom_mimetypes() +patch_socket_getaddrinfo()
indico/util/network.py+33 −1 modified@@ -9,6 +9,7 @@ import socket from urllib.parse import urlsplit +from flask import g, has_app_context from requests import Response from requests.exceptions import RequestException @@ -29,7 +30,7 @@ def is_private_url(url): return True try: - host_data = socket.getaddrinfo(hostname, None, 0, 0, socket.IPPROTO_TCP) + host_data = socket.getaddrinfo(hostname, None) return any(_is_private_ip(str(item[4][0])) for item in host_data) except (socket.gaierror, ipaddress.AddressValueError, ValueError): return True @@ -48,6 +49,8 @@ def validate_request_url(url: str): hook using ``hooks={'response': validate_redirect_target_hook}`` or ``**make_validate_request_url_hook()`` when making the request. """ + # Enable getaddrinfo interception to spot DNS rebinding attacks + g.setdefault('gai_cache', {}) # This could also allow for configurable whitelisting of specific hosts, but until # someone needs this let's keep it simple and just blacklist private ranges. if is_private_url(url): @@ -74,3 +77,32 @@ def make_validate_request_url_hook(): Use it like this: ``requests.get(..., **make_validate_request_url_hook())`` """ return {'hooks': {'response': validate_redirect_target_hook}} + + +def patch_socket_getaddrinfo(): + """Monkey-patch socket.getaddrinfo to check for DNS-rebinding attacks. + + This avoids SSRF via dns rebinding, where the first lookup in `validate_request_url` + returns a safe IP, but the second lookup (when making the actual connection) returns + a restricted IP. Once `validate_request_url` has been used, any subsequent lookups + for the same host are checked against the first one, and if a private IP shows up + in the result set, we abort. + """ + orig_gai = socket.getaddrinfo + + def safe_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): + rv = orig_gai(host, port, family, type, proto, flags) + if not has_app_context() or 'gai_cache' not in g: + return rv + cached_addrs = g.gai_cache.get(host) + addrs = {x[4][0] for x in rv} + if ( + cached_addrs is not None + and (new_addrs := (addrs - cached_addrs)) + and (offender := next((x for x in new_addrs if _is_private_ip(x)), None)) + ): + raise InsecureRequestError(f'Possible DNS rebinding attack for {host} -> {offender}') + g.gai_cache[host] = addrs + return rv + + socket.getaddrinfo = safe_getaddrinfo
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-f47c-3c5w-v7p4ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-25738ghsaADVISORY
- github.com/indico/indico/commit/70d341826116fac5868719a6133f2c26d9345137ghsax_refsource_MISCWEB
- github.com/indico/indico/releases/tag/v3.3.10ghsax_refsource_MISCWEB
- github.com/indico/indico/security/advisories/GHSA-f47c-3c5w-v7p4ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.