Overview
EcomScan is a realtime detection & response platform for ecommerce storefronts. It deploys as a lightweight CLI agent on your server, scans your codebase for Magecart skimmers, webshells, backdoors, and obfuscated malware, then streams results to a central dashboard with alerting, MITRE ATT&CK mapping, and AI-powered remediation.
Architecture
┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Storefront │ │ korp │ │ Dashboard │
│ /var/www/ │──────▶│ CLI agent │──────▶│ + API │
│ │ scan │ │ POST │ │
└─────────────┘ └──────────────┘ └────────────────┘
│ Signature engine │ Alerts
│ Hash engine │ Incidents
│ YARA rules │ Threat intel
│ Heuristic engine │ Compliance
│ Delta detection │ Webhooks
│ Attack chain └────────────────
└──────────────
Install the CLI
The korp CLI runs on Linux (x86_64 / arm64), macOS, and WSL. Install with a single command:
# Install korp CLI $ curl -fsSL https://github.com/ecomscan/korp/releases/latest | sh # Or with wget $ wget -qO- https://github.com/ecomscan/korp/releases/latest | sh
Manual install
# Download binary directly $ wget https://github.com/ecomscan/korp/releases/latest/download/korp-linux-amd64.tar.gz $ tar xzf korp-linux-amd64.tar.gz $ sudo mv korp /usr/local/bin/ $ korp --version
Docker
$ docker run --rm -v /var/www/html:/scan ecomscan/korp scan /scanVerify installation
$ korp --version korp v1.0.4 (build: 2026-05-13, commit: a8f3c2d) $ korp status CLI: v1.4.2 API: connected (https://api.ecomscan.io) License: EC-GROW-**** (Growth tier) Auth: authenticated as user@company.com
Quick start
Step 1: Authenticate
$ korp auth login Email: user@company.com Password: ******** ✓ Authenticated. Token saved to ~/.ecomscan/credentials.json
Step 2: Run a local scan
$ korp scan --path /var/www/html --platform magento ▸ Scanning /var/www/html (magento) ▸ 15,241 files scanned in 12.3s ▸ Engines: signature ✓ hash ✓ heuristic ✓ YARA ✓ delta ✓ ┌─────────────────────────────────────────────────────────┐ │ RISK SCORE: 78/100 (CRITICAL) │ │ Findings: 2 critical · 3 high · 1 medium · 0 low │ └─────────────────────────────────────────────────────────┘ CRITICAL Magecart · KeepUp.v3 /checkout/js/bundle.min.js CRITICAL PHP webshell · WSO 4.0 /pub/media/.thumbs/x.php HIGH Obfuscated eval chain /app/code/local/helper.php HIGH Exfil POST to 185.234.72.19 /skin/frontend/loader.js HIGH XOR-encoded payload /var/tmp/.cache.php MEDIUM Unsigned 3rd-party script /checkout/head.phtml
Step 3: Upload to dashboard
Uploading scan results requires an agent secret (ec_key_...), not your login JWT. Create one from the dashboard (API Keys → Create key) or during install:
# Option A: Install registers an agent and saves the secret $ korp install --license-key EC-GROW-XXXX-XXXX-XXXX \ --tenant-id YOUR_TENANT_UUID \ --store-id YOUR_STORE_UUID # Option B: Create a key from the dashboard or CLI $ korp keys create --name "prod-server" --store-id YOUR_STORE_UUID # Then scan + upload using the agent secret (set via --token or env) $ ECOMSCAN_TOKEN=ec_key_xxxxx korp scan \ --path /var/www/html \ --platform magento \ --upload ✓ 6 findings uploaded to dashboard ✓ 2 alerts created (CRITICAL, HIGH)
korp auth login gives you a JWT for read-only CLI commands (status, check, report, keys). Scan upload uses the X-Agent-Secret header with an ec_key_... token scoped to a specific store.Step 4: Start continuous monitoring
# Watch for file changes in real time $ korp monitor --path /var/www/html --platform magento ▸ Baseline created: 15,241 files hashed ▸ Watching /var/www/html for changes... ▸ Next scheduled scan: 6h0m0s ▸ Heartbeat: every 60s → api.ecomscan.io
License activation
After purchasing a plan you receive a license key. The prefix determines your tier:
| Prefix | Tier | Stores | Features |
|---|---|---|---|
| EC-STAR-**** | Starter | 1 | Scan, monitor, alerts |
| EC-GROW-**** | Growth | up to 10 | + YARA, IOC feed, API |
| EC-AGCY-**** | Agency | Unlimited | + Multi-tenant, white-label |
| EC-ENTR-**** | Enterprise | Unlimited | + SSO, RBAC, custom MITRE |
$ korp install --license-key=EC-GROW-XXXX-XXXX-XXXX ✓ License validated: Growth tier ✓ Agent registered: store-01-agent ✓ API key saved to ~/.ecomscan/credentials.json
Your first scan
What happens during a scan:
| Time | Phase | What happens |
|---|---|---|
| 0-2s | Discovery | Walk filesystem, filter by extension, skip excludes |
| 2-8s | Signature + hash | Match against 500+ signatures and known-bad hashes |
| 8-12s | YARA + heuristics | YARA rules fire, then behavioral analysis on every file |
| 12-15s | Delta + scoring | Compare against baseline, compute risk score per finding |
| 15s | Report | Generate unified report with family classification, MITRE mapping |
Routing alerts
Every detection produces an alert. Configure destinations in the dashboard under Integrations:
- Slack — channel per severity; rich card with remediate buttons.
- PagerDuty — auto-page on
critical; service mapped per store. - Webhook — signed payload (HMAC-SHA256), retried with exponential backoff.
- SIEM — Splunk HEC, Datadog, Elastic via native connectors.
- MS Teams — adaptive cards with one-click actions.
- Email — digest or per-incident, customizable templates.
Config file
The CLI reads config from ~/.ecomscan/config.yaml (or /etc/ecomscan/config.yaml for system-wide). All fields are optional — sensible defaults are applied.
# ~/.ecomscan/config.yaml agent: store_id: "550e8400-e29b-41d4-a716-446655440000" secret_key: "ec_key_xxxxx" api: endpoint: "https://api.ecomscan.io" timeout: 30s retry_max: 3 scanner: store_paths: - /var/www/html platform: magento scan_interval: 6h max_concurrency: 4 enable_heuristics: true enable_yara: true extensions: - .php - .phtml - .js - .html - .xml exclude_paths: - node_modules - vendor - .git monitor: enabled: true heartbeat_interval: 60s change_detection: true
Manage config via CLI
$ korp config show # View current config $ korp config set scan.concurrency 8 # Update a value $ korp config reset # Reset to defaults
Environment variables
Every config key can be set as an env var with the ECOMSCAN_ prefix. Env vars override the config file.
# Required for agent mode export ECOMSCAN_AGENT_STORE_ID="your-store-uuid" export ECOMSCAN_AGENT_SECRET_KEY="ec_key_xxxxx" export ECOMSCAN_API_ENDPOINT="https://api.ecomscan.io" # Optional overrides export ECOMSCAN_SCANNER_PLATFORM="magento" export ECOMSCAN_SCANNER_STORE_PATHS=""/var/www/html""
Agent daemon mode
The agent daemon runs continuously — scanning on a schedule, monitoring file changes, and sending heartbeats to the API.
# Start the agent daemon $ korp monitor \ --path /var/www/html \ --platform magento \ --scan-interval 6h # What the daemon does: 1. Creates filesystem baseline (SHA256 per file) 2. Watches for file modifications via fsnotify 3. Runs full scan every 6h (configurable) 4. Sends heartbeat to API every 60s 5. Uploads findings + change events automatically
Data flow
Agent daemon API server ──────────── ────────── Heartbeat (60s) ──────────────────▶ POST /api/v1/agents/heartbeat Scan results ──────────────────▶ POST /api/v1/scans/results File changes ──────────────────▶ POST /api/v1/events/file-change Auth header: X-Agent-Secret: ec_key_xxxxx
Deploy as a service
systemd (Linux)
# /etc/systemd/system/korp.service [Unit] Description=korp agent After=network.target [Service] Type=simple User=ecomscan ExecStart=/usr/local/bin/korp monitor --path /var/www/html --platform magento Restart=always RestartSec=10 Environment=ECOMSCAN_AGENT_SECRET_KEY=ec_key_xxxxx Environment=ECOMSCAN_AGENT_STORE_ID=your-store-uuid [Install] WantedBy=multi-user.target
$ sudo systemctl enable --now korp $ sudo systemctl status korp $ sudo journalctl -u korp -f # tail logs
Docker Compose
# docker-compose.yml services: korp: image: ecomscan/korp:latest command: monitor --path /scan --platform magento volumes: - /var/www/html:/scan:ro environment: ECOMSCAN_AGENT_SECRET_KEY: ec_key_xxxxx ECOMSCAN_AGENT_STORE_ID: your-store-uuid ECOMSCAN_API_ENDPOINT: https://api.ecomscan.io restart: unless-stopped
Kubernetes
# Deploy as a DaemonSet on nodes with storefronts apiVersion: apps/v1 kind: DaemonSet metadata: name: ecomscan-agent spec: selector: matchLabels: app: ecomscan template: spec: containers: - name: ecomscan image: ecomscan/korp:latest args: ["monitor", "--path", "/scan"] volumeMounts: - name: store mountPath: /scan readOnly: true envFrom: - secretRef: name: ecomscan-secrets
Magento & Adobe Commerce
$ korp scan --path /var/www/html --platform magentoAutomatically scans: app/code, app/design, pub/static, pub/media, var, generated. Understands Magento module structure, detects admin path obfuscation, and monitors env.php changes.
WooCommerce
$ korp scan --path /var/www/html --platform woocommerceScans wp-content/plugins, wp-content/themes, wp-includes. Monitors wp-config.php, .htaccess, and detects unauthorized plugins.
Shopify Plus
Shopify storefronts are scanned via the checkout extensibility API. No agent install needed — connect via the dashboard Integrations → Shopify.
Shopware
$ korp scan --path /var/www/html --platform shopwareSupports Shopware 5 and 6. Scans custom plugins, themes, and public/ assets.
Headless storefronts
$ korp scan --path /app/dist --platform other \
--extensions .js,.ts,.jsx,.tsxFor headless/custom builds, use --platform other and specify extensions. Heuristic and YARA engines work on any codebase.
How detection works
Every file passes through 6 detection engines in sequence. The unified pipeline normalizes, deduplicates, and scores all findings:
File │ ├──▶ 1. Signature engine 500+ regex patterns (webshells, skimmers, backdoors) ├──▶ 2. Hash engine Known-bad MD5/SHA256 database ├──▶ 3. YARA engine Community + ecomscan YARA rules ├──▶ 4. IOC matcher Domain, IP, hash indicators from threat feeds ├──▶ 5. Heuristic engine 40+ behavioral signals (entropy, obfuscation, exfil) ├──▶ 6. Delta detector Baseline diff — what changed since last scan? │ ▼ Unified Detection │ ├──▶ Family classification Match to 100+ known malware families ├──▶ Confidence calibration Engine reliability × context × rule override ├──▶ Risk scoring Evidence-weighted, path-aware, exploit-chain amplified ├──▶ MITRE ATT&CK mapping Technique + tactic assignment └──▶ Attack chain Kill-chain reconstruction across files
Magecart family detection
EcomScan tracks 28+ known Magecart families by fingerprint, plus behavioral classes:
- KeepUp.v3 — Image pixel exfiltration, card form hooks
- Inter / Inter2 — Injected via compromised 3rd-party scripts
- Grelos — Payment form overlay with data interception
- MakeFrame — Iframe-based card capture
- FormJacker — Form submit intercept + exfil
Unknown skimmers are caught via co-occurrence scoring: if a JS file on a checkout page has 3+ signals (form listener + card selector + beacon exfil), it's flagged even with no known signature.
File integrity monitoring
The integrity engine builds a SHA-256 baseline of every file under the monitored paths. On each scan, it compares the current filesystem against the baseline and flags:
- New files — unexpected files in web-accessible directories
- Modified files — changed content, especially in checkout/payment paths
- Deleted files — removed security controls or config files
- Permission changes — files made world-writable or executable
# Create a baseline after a clean deploy $ korp baseline --path /var/www/html ✓ Baseline created: 15,241 files tracked ✓ Saved to: ~/.ecomscan/baseline.json
Heuristic engine
The heuristic engine scores 40+ behavioral indicators without signatures:
| Signal | Score | Catches |
|---|---|---|
| eval() + base64_decode chain | +0.50 | Obfuscated PHP backdoors |
| Shannon entropy > 5.5 | +0.20 | Packed/encrypted payloads |
| XOR cipher loops | +0.35 | XOR-encoded malware |
| sendBeacon / fetch POST | +0.35 | JS exfiltration (Magecart) |
| Hidden iframes | +0.45 | Drive-by injection |
| exec/system + $_GET/$_POST | +0.50 | Remote code execution |
| Suspicious TLD (.su .xyz .tk) | +0.40 | C2 domain communication |
| Low whitespace ratio (<2%) | +0.20 | Minified/obfuscated code |
Verdict: score ≥ 0.70 = malicious, ≥ 0.35 = suspicious, < 0.35 = clean.
Delta detection
Compares each scan against the previous baseline. These file changes are auto-flagged at HIGH confidence even with zero signature matches:
- PHP file added to
/uploads/or/media/— executable in unexpected location - Checkout JavaScript modified since last scan — potential skimmer injection
- Core config changed (
wp-config.php,env.php,.htaccess) - New cron job file — persistence mechanism
MITRE ATT&CK mapping
Every detection is mapped to MITRE ATT&CK techniques. The attack chain reconstructor builds kill-chain narratives across multiple findings:
Initial Access ──▶ Execution ──▶ Persistence ──▶ Collection ──▶ Exfiltration T1195.002 T1059.007 T1505.003 T1056.003 T1041 Supply chain JavaScript Web shell Form capture C2 channel
CLI reference
# Scanning korp scan --path <dir> # Scan directory for malware korp scan --path <dir> --upload # Scan + upload to dashboard korp scan --path <dir> --report # Generate incident report korp scan --path <dir> --email X # Scan + email report korp scan --path <dir> --db-scan # Include WordPress DB scan korp baseline --path <dir> # Create file integrity baseline # Monitoring korp monitor --path <dir> # Real-time file watching + scans # Auth & setup korp auth login # Email/password login korp auth logout # Clear credentials korp install --license-key=EC-... # Activate license + register agent # Management korp keys list # List API keys korp keys create --name "prod" # Create API key (agent secret) korp keys revoke --key-id <id> # Revoke API key korp check <domain> # Quick store health check korp status # Agent + API status korp report --scan-id=X # Fetch scan report (JSON/CSV) korp config show # View config korp update # Update CLI binary korp version # Print version
Scan command flags
| Flag | Default | Description |
|---|---|---|
| --path <dir> | (required) | Directory to scan |
| --platform <type> | other | magento | woocommerce | prestashop | shopware | opencart | other |
| --severity <level> | low | Minimum severity to report: critical | high | medium | low |
| --format <type> | table | Output format: table | json | csv |
| --output <file> | stdout | Write report to file |
| --upload | false | Upload results to API |
| --store-id <uuid> | Store ID (required with --upload) | |
| --exclude <patterns> | Comma-separated glob patterns to skip | |
| --max-size <MB> | 10 | Max file size in MB |
| --concurrency <N> | CPU count | Parallel scan workers |
| --verbose | false | Debug logging |
| --json | false | Force JSON output (alias for --format json) |
| --no-color | false | Disable colored output |
Report format
When using --format json, the scan produces this structure:
{
"id": "scan-uuid",
"store_id": "store-uuid",
"started_at": "2026-05-13T04:18:00Z",
"completed_at": "2026-05-13T04:18:12Z",
"duration": "12.3s",
"platform": "magento",
"total_files": 15241,
"scanned_files": 14800,
"findings": [
{
"path": "/checkout/js/bundle.min.js",
"severity": "critical",
"confidence": 97,
"type": "magecart",
"family": "KeepUp.v3",
"mitre": "T1056.003",
"matches": [
{
"signature_name": "Magecart_KeepUp_v3_Loader",
"line": 42,
"matched_text": "addEventListener('change'...)",
"remediation": "Remove injected script, block exfil domain at edge"
}
],
"heuristic": {
"verdict": "malicious",
"score": 0.92,
"indicators": ["form-hook", "beacon-exfil", "card-selector"]
}
}
],
"summary": {
"critical": 2,
"high": 3,
"medium": 1,
"low": 0,
"risk_score": 78
}
}API
The EcomScan REST API uses two authentication modes:
Authentication
| Mode | Header | Used by |
|---|---|---|
| User JWT | Authorization: Bearer <jwt> | Dashboard, CLI (korp auth login), user-facing endpoints |
| Agent secret | X-Agent-Secret: <ec_key_...> | Deployed agents: heartbeat, scan upload, file-change events |
| Public | (none) | Auth routes (/auth/login, /auth/signup), license validation, health check |
User JWT endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/stores | List all stores |
| POST | /api/v1/stores | Register a new store |
| GET | /api/v1/stores/:id | Get store details |
| GET | /api/v1/stores/:id/scans | List scans for a store |
| POST | /api/v1/stores/:id/scans | Trigger a scan |
| GET | /api/v1/scans | List all scans (cross-store) |
| GET | /api/v1/scans/:id | Get scan detail |
| GET | /api/v1/scans/:id/findings | Get scan findings |
| GET | /api/v1/dashboard/summary | Dashboard summary stats |
| GET | /api/v1/incidents | List incidents |
| GET | /api/v1/incidents/:id | Get incident detail |
| GET | /api/v1/alerts | List alerts |
| POST | /api/v1/alerts/:id/ack | Acknowledge an alert |
| GET | /api/v1/keys | List agent API keys |
| POST | /api/v1/keys | Create agent API key |
| GET | /api/v1/auth/me | Current user profile |
| GET | /api/v1/settings | Workspace settings |
| GET | /api/v1/compliance/summary | Compliance score |
Agent secret endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/scans/results | Upload scan results |
| POST | /api/v1/agents/heartbeat | Agent heartbeat |
| POST | /api/v1/events/file-change | File change event |
Example
# List critical incidents $ curl https://api.ecomscan.io/api/v1/incidents?severity=critical \ -H "Authorization: Bearer ec_sk_..." { "data": [ { "id": "INC-2391", "store_id": "acmegear.com", "title": "Magecart KeepUp.v3 on /checkout", "severity": "critical", "risk_score": 78 } ] }
Webhooks
Subscribe to events in Dashboard → Integrations → Webhook. Payloads are signed with HMAC-SHA256 using your shared secret.
Events: scan.completed, alert.created, incident.opened, incident.resolved, store.compromised, agent.offline, integrity.diff.
Verify the signature:
expected = HMAC-SHA256(shared_secret, request_body) actual = request.headers["X-Ecomscan-Signature"] valid = constant_time_compare(expected, actual)
Terraform
The ecomscan Terraform provider lets you declare stores, alert routes, and integrity rules as code. Recommended for agencies with > 20 stores.
resource "ecomscan_store" "acmegear" {
name = "acmegear.com"
url = "https://acmegear.com"
platform = "magento"
scan_config {
interval = "6h"
platform = "magento"
store_paths = ["/var/www/html"]
}
}
resource "ecomscan_alert_route" "slack_critical" {
store_id = ecomscan_store.acmegear.id
provider = "slack"
severity = "critical"
channel = "#security-alerts"
}Troubleshooting
Agent not connecting
# Check connectivity $ korp status # Test API directly $ curl -s https://api.ecomscan.io/healthz # Verify credentials $ cat ~/.ecomscan/credentials.json # Run with debug logging $ korp scan --path /var/www/html --verbose
High false positive rate
- Exclude vendor directories:
--exclude node_modules,vendor,.git - Raise severity threshold:
--severity high - Framework files are automatically down-weighted (×0.6 confidence)
- Create a baseline after a clean deploy:
korp baseline --path /var/www/html
Scan too slow
- Increase concurrency:
--concurrency 8 - Skip large files:
--max-size 5(5 MB limit) - Exclude non-critical paths:
--exclude var/log,var/cache,media/catalog
Common errors
| Error | Fix |
|---|---|
| NOAUTH: credentials not found | Run korp auth login |
| license expired | Renew at app.ecomscan.io/billing |
| permission denied: /var/www/html | Run as the web server user or use sudo |
| upload failed: store not found | Verify --store-id matches a store in your dashboard |
| YARA: rules compilation failed | Update CLI: korp update (rules ship with binary) |
community.ecomscan.io or reach out to support@ecomscan.io. Enterprise customers get a dedicated Slack channel.