~/blog/hardened-wordpress-audit-with-zero-exploitsPOSTED
by Shady Nathan Tawfik · August 8, 2026 · 4 min

A Patched Estate With Six Findings And No Exploits: Reporting Discipline

A restaurant site behind a web application firewall. Every plugin was current, every known exploit failed, and the report still had six findings worth acting on.

Interactive[blog-2.0]

TL;DR: Every plugin was current, every known exploit failed, and the report still had six findings. I explain the reporting discipline of a negative assessment and what a misconfigured perimeter would have exposed.

The scenario

I ran this as a black-box review: no credentials, only the publicly visible surface. Here is what I saw before I touched anything.

A small hospitality business site on a current content platform behind a commercial web application firewall, with caching, statistics and a consent plugin. Assessment covered header posture, mail authentication, user enumeration, version disclosure and firewall fingerprinting.

I removed all identifying information. The target is described only by sector and technology class so the pattern can be reused.

The pattern

The pattern I recognised — and that I keep finding in similar estates:

An assessment behind a firewall produces a different document. The first change is that the vectors stop being the report and become the method: six vectors were planned, all six failed, and that fact is the headline. The second change is that everything worth reporting is now hygiene, because the exploitable layer is exactly what the firewall is covering.

That situation is where reporting discipline gets tested. The temptation is to inflate: to treat a version banner as a vulnerability, to describe an enumeration endpoint as account compromise. The alternative is to be precise about what was attempted, what the firewall returned, and what would still be exploitable if the firewall were ever misconfigured or bypassed. The second document is shorter, more useful and survives being read by an auditor.

The fingerprinting finding deserves separate mention because it is the one that changes how you should think about the perimeter. A firewall that identifies itself in every response is not doing you a favour; it tells an attacker which layer to think about, and it makes the estate appear to be protected by a product rather than by configuration. The response header is also a promise: it says the protection is expected to stay, which is an assumption worth verifying rather than trusting.

TL;DR: A restaurant site behind a web application firewall. Every plugin was current, every known exploit failed, and the report still had six findings worth acting on.

Findings

SeverityFindingEvidence
MEDIUMNo security headers on the public surfaceHSTS, frame protection and content-type protection absent
MEDIUMMail authentication soft-fail with no enforcement policySending domain spoofable
LOWUser enumeration through the read interfaceAuthor account and identifier exposed
LOWPlatform and plugin versions in generator metadataExact build identifiable
LOWFirewall fingerprint in a response headerPerimeter product identified
LOWNo published security contact fileNo coordinated disclosure channel

The attack path

Planned vectorsFirewallAll six blockedZero exploitable findingsHygiene findings remainValue: what a misconfigured perimeter would expose

Reproduction in my lab

Every command below targets a lab container I control. Nothing here is aimed at a live system.

Confirm the fingerprint and the header gaps on your own site

~/code/bash bash
$ curl -sI https://example.org/ | grep -iE 'x-ws|x-cdn|x-firewall|x-sucuri|x-cf-ray|^server:'
$ curl -sI https://example.org/ | grep -icE 'strict-transport-security|content-security-policy|x-frame-options|x-content-type-options|referrer-policy'
$ curl -so /dev/null -w '%{http_code}\n' 'https://example.org/.well-known/security.txt'

Detection in your own estate

Check the mail chain on a domain that sends mail

~/code/bash bash
$ dig +short TXT example.org | grep -i spf
$ dig +short TXT _dmarc.example.org
# note: no _dmarc answer is itself the finding

Remediation

Add the header baseline without touching the firewall rules

~/code/nginx nginx
# the firewall does not add response headers; the origin must
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;

Once an attacker gains access, they can perform the following actions:

No security headers on the public surface
Mail authentication soft-fail with no enforcement policy

Takeaways

  • A blocked vector is a result. Write it up as one.
  • Do not inflate a version banner into a vulnerability to fill a report.
  • State what a misconfigured perimeter would expose; that is the actionable part.
  • A firewall that identifies itself is a perimeter you should test, not trust.

For educational purposes only. Every reproducible command targets my own lab environment (localhost), never a live system. © 2026