Bug 2567260 (CVE-2026-123084)

Summary: CVE-2026-123084 python-pulpcore: pulpcore: Header content guard jq filter exposes the content-app environment
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: dranck, dschmidt, ehelms, jlanda, jmitchel, jpasqual, juwatts, kshier, lblicha, lbrazdil, mhulan, mminar, ogajduse, osousa, rbiba, rbobbitt, rchan, security-response-team, simaishi, smallamp, sskracic, stcannon, tpfromme, yguenane, zhunting
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
An **expression language injection** has been found in the HeaderContentGuard.permit function in publication.py of the content guard in the **Pulpcore** package. The guard is supposed to check a value in a request header. It saves a jq filter and runs that filter against the header when a client asks for content. The filter is not limited to the header, and jq's env builtin also returns the environment of the content process. A low-privileged network attacker or user who can create a header content guard and attach it to a distribution can save a filter that reads that environment. The content request is allowed or denied according to the filter result. Repeating the request lets that attacker or user recover the environment, including Pulp settings held there, such as the Django secret key or the database password.
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-11-05 11:43:06 UTC
HeaderContentGuard.permit in pulpcore/app/models/publication.py compiles jq_filter with jq.compile and does not restrict jq’s env builtin.

When jq_filter is set, permit base64-decodes the named request header, parses it as JSON, runs the stored filter, and compares the result with header_value using !=. A mismatch raises PermissionError. Handler._permit in pulpcore/content/handler.py calls permit for the distribution’s content guard and turns PermissionError into a denial. HeaderContentGuardSerializer accepts jq_filter as an unvalidated string. Only JSONDecodeError is caught around the jq call.

The allow-or-deny result is an oracle for the filter output. A filter that uses env reads the content-app process environment, so the caller can recover that environment, including PULP_SECRET_KEY and PULP_DATABASES__default__PASSWORD when those values were exported into the process. A value that exists only in the settings file is not part of that environment.

The caller must be able to create or change a header content guard and attach it to a distribution. Creation requires core.add_headercontentguard, which core.headercontentguard_creator grants. The creator hook assigns core.headercontentguard_owner. Attaching the guard is a change to the distribution’s content_guard. The content request that runs the filter needs no further account. Once the guard is attached, any client who can request that content receives the same allow-or-deny result.

Likely introduced in pulpcore 3.39.0 by commit 7a02719e9. The dependency at introduction was jq>=1.6.0, which provides the env builtin. The same jq.compile call is still present on main at publication.py:548.