Bug 2530995 (CVE-2026-87874)
| Summary: | CVE-2026-87874 community.general: community.general: memcached cache plugin deserializes untrusted pickle data from memcached, enabling cache-poisoning remote code execution on the Ansible controller | ||
|---|---|---|---|
| Product: | [Other] Security Response | Reporter: | OSIDB Bzimport <bzimport> |
| Component: | vulnerability | Assignee: | Product Security <prodsec-ir-bot> |
| Status: | NEW --- | QA Contact: | |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | unspecified | CC: | amctagga, aoconnor, bniver, eglynn, flucifre, gmeno, groman, jjoyce, jpretori, jschluet, lhh, mbenjamin, mburns, mgarciac, mhackett, sostapov, vereddy |
| Target Milestone: | --- | Keywords: | Security |
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | --- | |
| Doc Text: |
A flaw was found in the memcached cache plugin of the community.general Ansible
collection. Although its documentation states that records are stored in JSON
format, the plugin performs no explicit serialization and relies on
python-memcached, which pickles values on write and unpickles them on read.
Because memcached is unauthenticated and cache keys are predictable, an attacker
able to reach a network-exposed or shared memcached instance can write a crafted
pickle payload that is deserialized and executed on the Ansible controller when
the poisoned fact cache is next read, leading to remote code execution.
|
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: | |||
plugins/cache/memcached.py documents "JSON formatted" records (line 13) but imports neither json nor pickle and does no explicit (de)serialization. set() passes the Ansible facts dict directly to python-memcached with min_compress_len=1 (lines 214-217); get() returns the client result unchanged (lines 201-212). python-memcached auto-pickles non-str/int values (_FLAG_PICKLE) and, with min_compress_len set, compresses them (_FLAG_COMPRESSED) -> stored flags 9, and calls pickle.loads() on read. The sibling plugins/cache/redis.py uses explicit AnsibleJSONEncoder/Decoder (lines 189, 194). memcached has no authentication and the key is "ansible_facts<host>" (default prefix, lines 31/193-194), so an attacker with network reach to the memcached instance can poison a fact-cache entry that the controller unpickles on the next read, yielding code execution as the ansible user. Upstream: https://github.com/ansible-collections/community.general plugins/cache/memcached.py — UNFIXED (no PR; no public CVE) Affected file: plugins/cache/memcached.py (:13 docstring, :201-217 get/set)