Repository navigation
Conversation
CVE-2026-123084: HeaderContentGuard.permit() evaluated a jq filter coming from the API, and jq's env builtin and $ENV variable expose the environment of the content process. A user able to create a content guard could therefore read secrets such as the Django secret key or the database password. Compile user-supplied filters with env and $ENV shadowed, so the environment is unreachable while the rest of the jq language keeps working. The same helper is used by JSON header authentication. Also fail closed when a filter is invalid or produces no result, instead of raising a server error. Assisted-by: DeepSeek V4.1 Flash (EnMaaS)
The comparison of the jq result with header_value can be used as an allow/deny oracle to guess a secret one character at a time. Cover the slicing variants for both env and $ENV. Assisted-by: DeepSeek V4.1 Flash (EnMaaS)
- Close the wrapper on a new line so a stored filter ending in a # comment is not turned into a syntax error. - Reject invalid jq filters in HeaderContentGuardSerializer instead of storing them and denying every request behind the guard. - Log invalid filters at WARNING with the filter text, and empty results at DEBUG. - Treat non-ASCII base64 headers as an access denial rather than a 500. - Add unit tests for JSONHeaderRemoteAuthentication and make the malicious-filter cases actually fail on the vulnerable code. Assisted-by: DeepSeek V4.1 Flash (EnMaaS)
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CVE-2026-123084
HeaderContentGuard.permit()evaluates a jq filter supplied through the API. jq makes the environment of the running process available through theenvbuiltin and the$ENVvariable, so a user who is allowed to create a content guard can read secrets held in the content process, e.g. the Django secret key or the database password. The header value comparison turns the guard into a boolean oracle, which allows recovering a secret character by character.The same execution pattern exists in
JSONHeaderRemoteAuthentication.Fix
Compile user-supplied filters with both interfaces shadowed:
envresolves to a local definition and$ENVto a local binding, so neither can reach the process environment. Everything else in the jq language keeps working: property access, pipes,select,//, string interpolation,map,index,def,reduce,try.An allow-list of "pure JSON paths" was considered first, but it would reject filters that are already in use, e.g.
.roles[] | select(.active) | .name,.sub // ""or"\(.org_id)|\(.user.username)". Shadowing removes the capability leak without a syntax restriction.As a side effect,
import/includebecome syntax errors because they are only valid at the top level of a program.Fail closed
permit()andauthenticate()now catchValueError(invalid filter, invalid JSON) andStopIteration(filter produced no result) and deny access. Previously an invalid or empty filter raised an unhandled server error.Verification
Reproducer run inside a live Pulp container, with a canary value in the environment and a guard whose
jq_filterisenv.PULP_CVE_2026_123084_CANARY:Against the unpatched
HeaderContentGuard(checked out frommain):Against this branch:
601 passed, 9 skipped(oci-env agent test).pulpcore/tests/unit/test_jq_utils.py: 20 tests coveringenv,$ENV, aliasing,try///,reduce,label, module import, plus unchanged results for legitimate filters.pulpcore/tests/unit/test_content_guard.py: environment leak, complex filters and empty-result cases.ruff checkandruff format --checkclean.Follow-ups
pulp-servicehas its ownFeatureContentGuardwith a directjq.compile()call; it needs the same treatment (or should call this helper once it is released).Assisted-by: DeepSeek V4.1 Flash (EnMaaS)