This is a bad lock on a room that the attacker usually has to be invited into first
CVE-2025-0214 is a SQL injection in the third-party TMD Custom Header Menu extension for OpenCart. The public advisory says the vulnerable OpenCart 4 release is 4.0.0.1, with an older OpenCart 3 branch also affected, and the bug sits in admin-side handling of the headermenu_id parameter on routes reached through /admin/index.php; the parameter is fed into a database query without proper neutralization.
The vendor's MEDIUM 4.1 is still too generous for patch triage at enterprise scale. The decisive friction is that exploitation needs authenticated access to the OpenCart admin UI or a stolen valid admin session plus user_token, which makes this a *post-initial-access* bug in a relatively niche extension, not an internet-sweepable foothold; the public PoC and real data-exposure potential keep it above IGNORE, but not by much.
3 steps from start to impact.
Reach an OpenCart admin session
user_token are required for exploitation, and even demonstrates a browser-console PoC that assumes an already logged-in admin.- OpenCart store has the TMD Custom Header Menu extension installed
- Attacker has authenticated admin access, a stolen session, or equivalent admin-browser code execution
- Admin route is reachable
- This is not unauthenticated remote exploitation
- Many enterprises do not expose admin paths broadly to the internet
- Credential theft, session theft, or prior XSS/phishing is a separate compromise stage
headermenu_id payloads can catch it; otherwise detection is weak until after session compromise.Trigger the vulnerable admin route with public PoC
sqlmap, the attacker sends crafted requests to the extension's admin form route and injects SQL through headermenu_id. The gist shows boolean-based, error-based, time-based, and UNION-based techniques against the parameter once a valid user_token is present.- Valid admin
user_tokenin request - Extension route permissions available to the compromised account
- Database-backed vulnerable code path still present
- Attack complexity is higher than commodity one-shot exploits
- OpenCart user-group permissions can block extension-specific access for some admin roles
- Some patched or manually modified installs may already cast/escape the parameter
/admin/index.php.Exfiltrate or tamper with store data
sqlmap, which can include customer PII, order data, and any sensitive records stored in MySQL.- Vulnerable query executes with sufficient DB read/write capability
- Database contains sensitive customer or admin records
- Blast radius is generally limited to the affected store/app database
- An attacker already holding admin access often has other easier abuse paths inside OpenCart
- Operational noise from full dumping may be noticeable in DB or web logs
The supporting signals.
| In-the-wild status | No authoritative evidence of active exploitation found in public sources reviewed. Not listed in CISA KEV. |
|---|---|
| Proof-of-concept availability | Yes. Researcher mcdruid published a public advisory and PoC, including browser-console exploitation and sqlmap output: GitHub Gist. |
| EPSS | User-supplied EPSS is 0.00112, which is extremely low in absolute terms. Percentile was not confirmed from an authoritative EPSS score page during review. |
| KEV status | No. CISA's Known Exploited Vulnerabilities Catalog does not contain CVE-2025-0214. |
| CVSS vector reality check | CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:L correctly captures the biggest suppressor: high privileges required. In practice that means *post-auth admin abuse*, not fresh external compromise. |
| Affected versions | Public advisory names TMD Custom Header Menu 4.0.0.1 on OpenCart as vulnerable and says an OpenCart 3 release from 2017 is also affected. Testing in the advisory was done against OpenCart 4.0.2.3 and 3.0.4.0 with the extension installed. |
| Fixed version | The researcher timeline says TMD released a fix on 2024-12-30, but a public version number was not verified from accessible vendor pages. Treat version validation as manual until you confirm the installed package contents. |
| Exposure / scanability | This is not broadly internet-sweepable the way pre-auth web bugs are, because the vulnerable path sits behind /admin and needs a valid session plus token. Public internet-scale exposure telemetry specific to this extension was not located; the extension page shows substantial marketplace visibility/download interest, but that is not exposure proof. |
| Disclosure timeline | Researcher timeline: reported 2024-12-27, vendor acknowledged 2024-12-28, fix released 2024-12-30, CVE requested 2025-01-03; NVD publication date 2025-01-04. |
| Reporter / source | Reported by mcdruid, with the CNA/source shown as VulDB in the NVD record. |
noisgate verdict.
The single most important factor is the attacker position requirement: this bug needs authenticated OpenCart admin access or a stolen admin session plus user_token. That turns a technically real SQLi into a *post-compromise privilege-abuse issue* in a niche extension, which sharply limits reachable population and attacker ROI.
Why this verdict
- Major downgrade for attacker position: exploitation needs admin-panel access, a stolen admin cookie, or admin-browser script execution. That is already a serious prior compromise stage.
- Population is narrow: this is a third-party OpenCart extension, not OpenCart core, so the exposed estate is a small subset of ecommerce installs rather than a broad enterprise platform surface.
- Threat pressure is weak: no KEV entry, no confirmed active exploitation, and the supplied EPSS is extremely low despite public PoC availability.
Why not higher?
If this were unauthenticated or even low-privilege authenticated, it would climb fast because SQLi against a live store database is nasty. But requiring high privileges plus a valid session token means most attackers who can use this have already crossed the hard boundary.
Why not lower?
This is still genuine SQL injection with a public PoC, not a theoretical bug. On a live store, successful abuse can expose customer data, admin credentials, and order records, so defenders should not dismiss it outright if the extension is present.
What to do — in priority order.
- Restrict admin reachability — Put
/adminbehind IP allowlists, VPN, or an identity-aware proxy so fewer attackers can ever satisfy the precondition. For a LOW verdict there is no SLA; treat as backlog hygiene, but this is the best risk-reduction move if you cannot patch immediately. - Audit admin roles — Review OpenCart user groups and remove extension access from anyone who does not need it; the exploit path dies if the compromised user cannot reach the module route. For a LOW verdict there is no SLA; treat as backlog hygiene, but make it part of the next permissions review.
- Hunt for session misuse — Search reverse-proxy and application logs for suspicious
/admin/index.phprequests containingheadermenu_id=with SQL metacharacters, especially from unusual IPs or admin accounts. For a LOW verdict there is no SLA; treat as backlog hygiene, but do it promptly if the store handles regulated customer data. - Disable or remove the extension if unused — If the business does not actively use TMD Custom Header Menu, removing the plugin is cleaner than carrying a low-value third-party risk surface. For a LOW verdict there is no SLA; treat as backlog hygiene, and this should be part of normal extension rationalization.
- A generic perimeter WAF is not enough, because the vulnerable route is typically behind authenticated admin access and the exploit can ride a valid session.
- Password rotation alone does not solve stolen-session scenarios; the advisory explicitly discusses valid session cookies and
user_tokenuse. - Relying on unauthenticated external scanning will miss most of the real exposure because the vulnerable code path is in the admin plane.
Crowdsourced verification payload.
Run this on the target OpenCart host against the web root, for example: sudo bash verify-cve-2025-0214.sh /var/www/html. Read access to the OpenCart files is required; root is helpful but not mandatory if the web tree is readable.
#!/usr/bin/env bash
# verify-cve-2025-0214.sh
# Check OpenCart filesystem for the TMD Custom Header Menu extension and look for
# unsanitized use of the headermenu_id parameter in admin-side PHP code.
#
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
set -u
WEBROOT="${1:-}"
if [[ -z "$WEBROOT" || ! -d "$WEBROOT" ]]; then
echo "UNKNOWN: usage: $0 /path/to/opencart/webroot"
exit 2
fi
# Candidate files/dirs commonly seen for this extension across OC3/OC4 layouts
mapfile -t CANDIDATES < <(find "$WEBROOT" \
\( -iname '*tmdcustomheader*' -o -iname '*headermenu*' \) \
2>/dev/null)
if [[ ${#CANDIDATES[@]} -eq 0 ]]; then
echo "UNKNOWN: no TMD Custom Header Menu extension artifacts found under $WEBROOT"
exit 2
fi
VULN_FOUND=0
PATCHED_FOUND=0
VERSION_HIT=0
for f in "${CANDIDATES[@]}"; do
if [[ -f "$f" ]]; then
# Version hint
if grep -Eq '4\.0\.0\.1' "$f" 2>/dev/null; then
VERSION_HIT=1
fi
# Look for direct request usage around headermenu_id
if grep -Eq "headermenu_id" "$f" 2>/dev/null; then
# Patched indicators: explicit cast or escaping applied to headermenu_id
if grep -Eq "\(int\)[^\n]*headermenu_id|intval\([^\n]*headermenu_id|escape\([^\n]*headermenu_id" "$f" 2>/dev/null; then
PATCHED_FOUND=1
fi
# Vulnerable indicators: raw request parameter pulled and later used in query-building code
if grep -Eq "request->get\['headermenu_id'\]|\$_GET\['headermenu_id'\]" "$f" 2>/dev/null; then
if grep -Eq "db->query\(|SELECT |UPDATE |DELETE |INSERT " "$f" 2>/dev/null; then
if ! grep -Eq "\(int\)[^\n]*headermenu_id|intval\([^\n]*headermenu_id|escape\([^\n]*headermenu_id" "$f" 2>/dev/null; then
VULN_FOUND=1
fi
fi
fi
fi
fi
done
if [[ $VULN_FOUND -eq 1 ]]; then
if [[ $VERSION_HIT -eq 1 ]]; then
echo "VULNERABLE: extension artifacts include version 4.0.0.1 and unsanitized headermenu_id handling"
else
echo "VULNERABLE: unsanitized headermenu_id handling found in TMD Custom Header Menu code"
fi
exit 1
fi
if [[ $PATCHED_FOUND -eq 1 ]]; then
echo "PATCHED: extension present and headermenu_id appears to be cast/escaped before query use"
exit 0
fi
echo "UNKNOWN: extension artifacts found, but vulnerable/patched state could not be determined conclusively"
exit 2
If you remember one thing.
/admin exposure and admin-role permissions as cheap guardrails.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.