A passive security audit checks the publicly observable security posture of any website โ without sending malicious payloads or probing for vulnerabilities. This guide walks through every check our Security Audit tool runs, why each one matters, and exactly how to fix any that fail. Pair this guide with the example report to see a real audit output.
A passive audit only inspects information your site already exposes to any visitor: HTTP response headers, the TLS handshake, public DNS records, and the rendered HTML. Nothing is sent that could be considered an attack. That makes it safe to run against any domain you have permission to scan, including production, and means it will not trigger your WAF or intrusion detection.
This audit covers 23 individual checks across 9 families. Each check is tagged with the relevant OWASP Top 10 category and CWE identifier so findings map cleanly onto the standard vulnerability taxonomy used by security teams.
Six response headers do most of the heavy lifting for browser-side protection. They cost nothing to deploy, work in every modern browser, and stop entire classes of attack.
CSP tells the browser which sources are allowed to load scripts, stylesheets, fonts, frames and other resources. A well-tuned CSP is the single strongest defence against cross-site scripting (XSS), which remains one of the most common web vulnerabilities. Start strict and loosen as needed:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'
frame-ancestors in CSP instead of (or in addition to) X-Frame-Options. CSP frame-ancestors is the modern replacement and supports finer-grained control.HSTS tells browsers to refuse to connect to your site over plain HTTP, even if the user types http:// in the address bar. This closes the small window where a man-in-the-middle attacker could downgrade the first request before the redirect to HTTPS.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
preload after testing โ it cannot easily be removed once you submit your domain to the HSTS preload list.Stops other sites embedding your pages in an iframe. The classic clickjacking defence โ without it, an attacker can overlay your login form inside a malicious page and steal credentials. Either header passes the check:
X-Frame-Options: SAMEORIGIN
Or, preferred:
Content-Security-Policy: frame-ancestors 'self'
Stops browsers second-guessing the Content-Type header through MIME sniffing. Without it, a file you serve as text/plain could be interpreted as JavaScript and executed. One line, one config option:
X-Content-Type-Options: nosniff
Controls how much of the originating URL is sent in the Referer header when a user clicks a link to another site. The right setting protects user privacy and prevents leaking session-bearing URLs:
Referrer-Policy: strict-origin-when-cross-origin
Disables browser features that your site does not need. If you do not use the camera, microphone or geolocation, deny them and remove an entire class of supply-chain risk from compromised third-party scripts:
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()
The TLS check opens an actual handshake to port 443 and inspects the certificate plus the negotiated protocol. Three things must be true:
| Check | Pass condition |
|---|---|
| Certificate valid | Signed by a trusted CA, not expired, not revoked |
| Not expiring soon | Valid for at least 30 more days |
| Modern protocol | Server negotiates TLS 1.2 or TLS 1.3 โ never TLS 1.0 or 1.1 |
Every Set-Cookie response should set three attributes. If a site sets cookies on the homepage, the audit checks all of them:
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/
Secure โ cookie is only sent over HTTPSHttpOnly โ JavaScript cannot read the cookie (defence against XSS-based session theft)SameSite=Lax or Strict โ defends against CSRFIf your page is served over HTTPS but loads any http:// resources, browsers will either block them (modern behaviour) or downgrade the connection (older behaviour). Either way, you lose. The audit scans the homepage HTML for any script, link, img, iframe or source tag pointing at an unencrypted URL.
http://, and analytics or chat widgets configured pre-HTTPS migration.Two response headers commonly leak version information that makes an attacker's job easier:
Server: nginx/1.18.0 X-Powered-By: PHP/7.4.0
An attacker now knows your nginx and PHP versions before lifting a finger. Strip them. In nginx:
server_tokens off; fastcgi_hide_header X-Powered-By; proxy_hide_header X-Powered-By;
In Apache:
ServerTokens Prod ServerSignature Off Header unset X-Powered-By
In PHP, also set expose_php = Off in php.ini.
When the audit identifies a software version from the Server or X-Powered-By header, or a CMS generator meta tag, it builds a CPE 2.3 identifier and queries the National Vulnerability Database for matching CVEs.
| Detected | CPE vendor:product |
|---|---|
| nginx/X.Y.Z | f5:nginx |
| Apache/X.Y.Z | apache:http_server |
| PHP/X.Y.Z | php:php |
| Microsoft-IIS/X.Y | microsoft:internet_information_services |
| OpenSSL/X.Y.Z | openssl:openssl |
| WordPress X.Y.Z | wordpress:wordpress |
| Drupal X.Y.Z | drupal:drupal |
| Joomla X.Y.Z | joomla:joomla! |
Results are cached for 24 hours per CPE to keep scans fast and avoid hammering NVD. If your site does not expose any version strings, this check passes by default โ no fingerprint, nothing to look up. That is the desired outcome.
The audit looks for three signals on the homepage:
<meta name="generator" content="WordPress 6.4.2"> โ most commonX-Generator response header (used by Drupal)/wp-content/, /wp-includes/ or /sites/default/Detection itself is not a fail. The fail is when the generator tag exposes the exact version, because that turns CMS detection into a one-step CVE lookup for an attacker. Remove the generator meta:
// WordPress functions.php
remove_action('wp_head', 'wp_generator');
Even sites that do not send email get impersonated. Without SPF, DKIM and DMARC records, anyone can send mail from @yourdomain.com and have it land in inboxes. The audit checks three TXT records on the apex of your domain (the www. prefix is stripped automatically):
# SPF (TXT on apex) v=spf1 include:_spf.google.com -all # DMARC (TXT on _dmarc.yourdomain.com) v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com # DKIM (TXT on <selector>._domainkey.yourdomain.com) v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GN...
DKIM uses per-vendor selectors so the audit probes the most common ones (default, google, selector1, selector2, k1, s1, s2, mail). If your provider uses a different selector the check may show no result even though DKIM is configured โ check your email provider's documentation.
Two standard well-known files round out the audit.
Crawlers expect /robots.txt to exist. Even an empty file is preferable to a 404, which floods server logs with crawler errors and signals an under-maintained site.
Defines how security researchers should report vulnerabilities they find on your site. Publish it at /.well-known/security.txt:
Contact: mailto:security@yourdomain.com Expires: 2027-12-31T23:59:59.000Z Policy: https://yourdomain.com/security-policy.html Preferred-Languages: en
Required fields are Contact and Expires. Everything else is optional but useful. Without security.txt a researcher who finds a bug has no obvious place to report it, and may resort to public disclosure.
Each check has a weight reflecting its impact. TLS validity and protocol weight heaviest (10 and 8 points respectively), header checks are mid-weight (4โ8), and informational checks like robots.txt presence are light (2). Warnings (for example a certificate expiring in 30 days, or a CMS exposing its version) score half-credit rather than zero. The total weight is 109 points, normalised to a score out of 100.
dig TXT yourdomain.com.Scan your domain across 23 passive security checks. Get OWASP and CWE-tagged findings with specific fix instructions for everything that fails.
Run free security audit โ