Blog

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:

  1. Recon — night scans for typical webshells and platform paths.
  2. RCE — an active shell in a known module’s cache (executable PHP in a cache directory).
  3. Escalation — locate the config file → DB credentials → KPI queries (not a full customer dump through that channel).
  4. 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:

  1. Treat weird UX as a potential incident until malware is ruled out.
  2. Forensic copy first, cleanup second — snapshot/image the live instance (and DB) before eradicate; otherwise you lose evidence and risk inconsistent data.
  3. Credentials burn faster than you think — after RCE or a config leak, rotate DB and accounts immediately, not “after cleaning the JS”.
  4. Cache and uploads are code — if PHP can execute there, it is a vector.
  5. Every user field in the BO is XSS waiting to happen without escaping.
  6. Contain → eradicate → harden → document — without the last step you have no history for a DPO / regulator / insurer.
  7. 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”.