Bug 2523431 (CVE-2026-79717)

Summary: CVE-2026-79717 galaxy_ng: galaxy_ng: blind SSRF via namespace avatar_url with no private-address restriction
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security <prodsec-ir-bot>
Status: NEW --- QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: dschmidt, jlanda, kshier, simaishi, stcannon, teagle, yguenane
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A server-side request forgery (SSRF) vulnerability was found in galaxy_ng, the Ansible Galaxy server plugin for Pulp. An authenticated user with namespace management permissions can set a namespace avatar URL to an arbitrary address, including internal networks, loopback, or cloud instance metadata endpoints. A background worker fetches that URL without checking the destination, which lets the attacker probe internal services and enumerate reachable IP addresses. The HTTP client is also configured without an overall timeout, so a slow or non-responsive target can pin workers and cause a denial of service.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description OSIDB Bzimport 2026-08-25 13:42:26 UTC
galaxy_ng is a Pulp plugin powering Ansible Galaxy and Ansible Automation Platform Private Automation Hub. A server-side request forgery (SSRF) exists in the namespace avatar download path.

In galaxy_ng/app/api/v3/serializers/namespace.py, avatar_url is a DRF URLField. That field validates URL syntax and scheme (http/https) only. It does not resolve the hostname or filter private, loopback, link-local, or cloud-metadata addresses. On namespace create, download_logo is always True. On update, download_logo is True whenever avatar_url is present. The serializer then dispatches a Pulp task that calls _download_avatar() in galaxy_ng/app/tasks/namespaces.py.

_download_avatar() builds an aiohttp session with ClientTimeout(total=None, sock_connect=600, sock_read=600) and passes the user-supplied URL to pulpcore HttpDownloader with no address restriction and no redirect-target revalidation. The Pulp worker therefore requests whatever address the publisher supplied, including RFC1918, 127.0.0.0/8, 169.254.0.0/16, and cloud metadata endpoints.

The SSRF is blind: the response is stored only if it passes image validation (PIL ImageField or SVG). Non-image bodies are discarded, so this is not direct credential exfiltration. The attacker still gets a binary oracle via namespace avatar_sha256 (updated vs unchanged), which is enough to enumerate reachable internal IPs and ports from the worker's network. The total=None timeout also lets a slow or hanging target pin a worker, which is a denial-of-service angle.

Privilege required is an authenticated user with galaxy.change_namespace or galaxy.add_namespace. In community Galaxy that includes a user's own namespace.

Affected: galaxy_ng (verified on current main, HEAD 2bc7189 at clone time). No upstream fix identified in the examined tree.
Reporter: Arpit Jain (GitHub arpitjain099), independent security researcher.
PSIRT ticket: PSIRTSUPT-22101
Distinct from GHSA-hc3x-6pf5-pmj3 (legacy role import path).