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: vulnerabilityAssignee: Product Security <prodsec-ir-bot>
Status: NEW --- QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: 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:

Description OSIDB Bzimport 2026-09-09 14:47:29 UTC
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)