Posts
E-commerce security — three attack paths I see in practice
Stolen admin credentials, a skimmer hiding behind a “checkout bug”, and injection in an order comment — what real incidents share, and the checklist I take from them.
On the shops I work with, breaches rarely look like a movie. There is no Hollywood zero-day on screen. There is an admin session, a weird checkout, or an injection attempt in a field nobody treats as an attack surface.
Below are three anonymized cases — different platforms, different vectors, one shared takeaway: a business signal is often the first security alert, and after an incident what matters is not only cleanup but documentation (including under GDPR / local breach-notification rules). No payloads, no passwords, no customer identifiers.
Before the timelines: in the PHP / e-commerce ecosystem these stories rarely start with a magic zero-day. Underneath you usually find something from this list — no 2FA on the admin panel, weak or shared credentials (panel, SSH/SFTP, FTP), overdue core and plugin/module updates, or supply chain: an unchecked marketplace plugin/theme that brings a vulnerability or malicious code. The cases below are concrete scenarios on that ground.
Case 1: WordPress admin, stolen password, malware in plugins
A mid-size WordPress + WooCommerce store. Classic setup: customer data in orders, Cloudflare in front of hosting, the admin panel as the main control plane.
Overnight an attacker entered the panel and dropped a typical post-compromise kit: a webshell, a plugin that kept a hidden admin, and a downloader (the last one looked unused in the logs). Activity lasted around a dozen hours; detection came at midday — odd files and a broken admin UI. Cleanup took about an hour; then hardening and documentation.
Cause
Most likely vector: compromised login credentials (infostealer / leak), not defeating CAPTCHA. An outdated shop component was considered as an alternative, without hard proof. WAF/CDN logs showed activity from the WP panel, including the plugin upload path.
Consequences
- unauthorized admin access and persistence under
wp-content, - personal-data risk (potential access existed),
- a broken admin UI as a paradoxical detection signal — one component interrupted normal execution.
What I checked for customer data
Potential access ≠ an automatic personal-data breach. The assessment was log-based: no unusual outbound connections, no traffic spike, no paths typical of DB dumps in the attacker’s traffic, malware that did not look like targeted exfiltration. Documentary conclusion: low risk + fast response → a reasoned decision not to notify the supervisory authority — but with a written note, timeline and DPO analysis, not “ignore the topic”.
Countermeasure
Contain → eradicate → harden → document. Before I delete anything on a live instance, I take a quick snapshot / image (disk + database state) — material for forensics and a guard against losing data consistency. Only then: remove artefacts and the attacker account, a gate in front of admin (htpasswd), lock writes in the plugins directory, change the database password, update core and plugins, enable a scanner/WAF with alerts, hide the login URL, rotate passwords (including htpasswd), turn on 2FA for admins, set up 3-2-1 backups with log retention, tighten the FTP/WP account audit and write down the procedures. None of that stayed on a “later” list — hardening went out with the cleanup.
Lesson: most WP shop breaches I see are still credentials + panel, not an exotic exploit.
Case 2: “coupon code bug” — Magecart + RCE underneath
Another shop — PrestaShop. The client ticket sounded like an urgent UX issue: a coupon in the cart jumped straight to payment; some orders lacked a phone number; “payment fails”. After a short look it was clear this was not a checkout regression.
What was really happening
Simplified kill chain:
- Recon — night scans for typical webshells and platform paths.
- RCE — an active shell in a known module’s cache (executable PHP in a cache directory).
- Escalation — locate the config file → DB credentials → KPI queries (not a full customer dump through that channel).
- Monetization — a separate track: a skimmer posing as the payment layer (loader in
head+ a “GTM-like” endpoint on a foreign domain). It collected customer and card data; after theft, “payment fail”, and the script did not run again.
Skimmer window: from file drop to removal — on the order of days, because the first signal looked like a front-end bug.
Cause / consequences
Cause: an outdated / vulnerable module + cache treated as a safe place for code. Consequences: RCE (persistence, shop “valuation”) and a card skimmer (separate harm). No customer dump in SQL does not mean no harm — cards left through another channel.
Countermeasure
Remove skimmer and loaders, verify themes/modules for reinfection, patch the vulnerable module, rotate the DB password immediately (credentials were already in attacker hands), reset back-office passwords, audit uploads. Instead of blindly deleting the shell path — a honeypot that catches returns. Business/legal: order window under GDPR/local rules, contact the payment operator on card leakage.
Lesson: odd checkout + broken validation is a security red flag, not only a QA ticket. RCE and Magecart are two goals — remediation must cover both.
Case 3: injection in an order comment (custom shop)
The third case is simpler and for that reason important. In a custom shop someone tried to inject JavaScript, PHP and SQL through an order comment. Early payloads looked like probing — checking whether injection worked at all. Some scripts did nothing; the only one that “made it” into storage showed up in admin as text — and that was it. No luck involved: order-comment content was run through HTML escaping on BO render (plus sanitization on write). The browser got a safe string, not executable code, so admin XSS never started.
Cause / consequences / countermeasure
Cause: a user-content field treated as harmless — while it lands in the back office. Consequences: without escaping, classic admin XSS (admin session, cookie theft, further escalation). Countermeasure: escape on display, validate on write, CSP where it helps, review every place order text is rendered as HTML.
Lesson: the attack surface is not only /admin/login. It is every field an employee will eventually see in the panel.
What these three stories share
| Case 1 (WP) | Case 2 (Presta) | Case 3 (custom) | |
|---|---|---|---|
| First signal | broken admin / odd files | “checkout bug” | probing in a comment |
| Entry | credentials → panel | RCE in module/cache | injection in a BO field |
| Goal | persistence / access | card skimmer + shell | vulnerability test / XSS |
| Remediation | cleanup + harden + GDPR paper | patch + rotate secrets + honeypot | escape + validation |
Common rules I apply on e-commerce work:
- Treat weird UX as a potential incident until malware is ruled out.
- Forensic copy first, cleanup second — snapshot/image the live instance (and DB) before eradicate; otherwise you lose evidence and risk inconsistent data.
- Credentials burn faster than you think — after RCE or a config leak, rotate DB and accounts immediately, not “after cleaning the JS”.
- Cache and uploads are code — if PHP can execute there, it is a vector.
- Every user field in the BO is XSS waiting to happen without escaping.
- Contain → eradicate → harden → document — without the last step you have no history for a DPO / regulator / insurer.
- A system intrusion attempt ≠ an automatic personal-data breach — but the assessment must be written down, not “by feel”.
Checklist I leave after such cases
- Snapshot / image before any cleanup on production
- 2FA (or a second factor) for every admin — plus strong passwords / rotation for SSH·SFTP·FTP
- Regular updates of core, themes and modules — especially those with cache/upload; plugins only from trusted sources
- File-integrity scanner + alerts
- 3-2-1 backups and log retention (access + WAF/CDN)
- Escape/sanitize all user content in the panel
- Rotate secrets after every confirmed RCE / config leak
- Procedure: who declares the incident, who writes the timeline, who talks to the DPO
- After a card skimmer: contact the payment operator, not only “clean the JS”
Summary
Shop security is not one WAF product and not one plugin. It is a habit: read odd front-end behaviour as a signal, assume the panel will fall to a password before a zero-day, and after cleanup leave paper, not only a clean disk. The three cases above are anonymized but repeatable — credentials, Magecart behind a “bug”, injection in an innocent field. I see those more often than spectacular zero-days. That is why a playbook is worth having before someone calls about an “urgent cart bug”.