Last quarter, a friend who runs a tiny SaaS told me something that stayed with me: “We didn’t get hacked. We just never saw the warning email.”
A security researcher had found an exposed debug endpoint. They did what good researchers do, tried to report it, and bounced between a generic contact form, a dead support inbox, and a social DM that nobody monitored. By the time the team noticed unusual traffic, the issue had already been shared in a private forum.
That story is exactly why security.txt exists. Not as a silver bullet, not as compliance theater, but as a clear front door for vulnerability reporting.
In this guide, I will show you how to implement security.txt for WordPress in a way that is practical for small teams: standards-aligned, easy to maintain, and resistant to spam chaos. If you already run a hardened WordPress stack, this is a low-effort upgrade that materially improves your incident readiness.
The small file that closes a very real gap
RFC 9116 defines a machine-readable file, typically hosted at /.well-known/security.txt, where you publish security contact and disclosure policy details. The goal is simple: make responsible reporting easier and less ambiguous.
Three implementation facts matter in practice:
- The canonical location is
/.well-known/security.txtover HTTPS. ContactandExpiresare the minimum fields you should treat as mandatory in real deployments.- RFC 9116 recommends digital signatures for authenticity when possible.
If this reminds you of “security is risk reduction, not risk elimination,” that framing is straight in line with the WordPress hardening guidance: choose controls that reduce practical risk and keep them maintained.
How this fits your existing 7tech-style security posture
If you have already tightened browser defenses (for example, with a strict CSP rollout), hardened session handling behind reverse proxies, and made plugin updates reversible, security.txt becomes the communication layer that ties those controls together.
Related playbooks on 7tech:
- Strict CSP rollout on WordPress
- Secure PHP session cookies behind Nginx and Cloudflare
- Staged plugin rollout and rollback runbook
- WordPress cron reliability playbook
Think of it this way: hardening controls reduce attack surface, while disclosure channels reduce response latency when something slips through.
A production-friendly security.txt template
Start with a lean file. Keep it accurate, then enrich over time.
Contact: mailto:security@7tech.co.in
Contact: https://www.7tech.co.in/security-report/
Expires: 2026-10-31T23:59:00.000Z
Preferred-Languages: en, hi
Canonical: https://www.7tech.co.in/.well-known/security.txt
Policy: https://www.7tech.co.in/vulnerability-disclosure-policy/
Acknowledgments: https://www.7tech.co.in/security-hall-of-fame/
Tradeoff notes:
- Email only is simplest, but vulnerable to deliverability issues and spam flooding.
- Web form only helps triage, but can block researchers who want encrypted contact.
- Both channels is usually best for smaller teams, with clear routing and expectations.
Keep Expires realistic. A short expiration (for example 3–6 months) forces operational freshness.
Serving it correctly on WordPress + Nginx
You can host the file physically in your web root, but many teams prefer an explicit Nginx location so behavior stays predictable during theme/plugin churn.
# /etc/nginx/sites-available/7tech.co.in
location = /.well-known/security.txt {
default_type text/plain;
add_header Cache-Control "public, max-age=3600";
try_files $uri =404;
}
# Optional fallback for clients checking /security.txt
location = /security.txt {
return 301 https://$host/.well-known/security.txt;
}
If you terminate TLS at Cloudflare or another edge, verify the file is still reachable at the origin URL and final public URL. Redirect loops here are common during first deployment.
Operational guardrails most blogs skip (and later regret)
Publishing the file is step one. Operating it is where value appears.
- Route security mailbox to a ticket queue with SLA tags.
- Define a first-response target (for example, 48 business hours).
- Store proof artifacts (request/response samples, logs with redaction) for reproducibility.
- Separate vulnerability reports from support noise using mailbox filters and keywords.
For small teams, a lightweight health check via cron or systemd timer is enough:
#!/usr/bin/env bash
set -euo pipefail
URL="https://www.7tech.co.in/.well-known/security.txt"
BODY="$(curl -fsSL "$URL")"
grep -q '^Contact:' <<<"$BODY"
grep -q '^Expires:' <<<"$BODY"
# warn if expires in less than 14 days
EXP="$(awk -F': ' '/^Expires:/{print $2}' <<<"$BODY")"
python3 - <<'PY' "$EXP"
from datetime import datetime, timezone
import sys
exp = datetime.fromisoformat(sys.argv[1].replace('Z', '+00:00'))
left = exp - datetime.now(timezone.utc)
if left.days < 14:
raise SystemExit("security.txt expires in <14 days")
print("security.txt check ok")
PY
This script does not replace security monitoring, but it prevents the most embarrassing failure mode: an expired disclosure channel.
What your vulnerability policy page should say (without legal theater)
Your Policy: URL in security.txt should not be a vague paragraph. It should answer the operational questions a researcher has in the first five minutes:
- Scope: Which domains, APIs, and mobile apps are in scope right now.
- Out of scope: Explicitly list social engineering, DDoS, and physical testing if not permitted.
- Safe handling expectations: No data exfiltration, no service disruption, minimum proof needed.
- Response timeline: When reporters should expect acknowledgement and next update.
- Disclosure model: Private/coordinated disclosure preferred, with escalation path if unresponsive.
This is where tradeoffs become real. A strict policy lowers legal ambiguity but can discourage good-faith reports if written aggressively. A loose policy feels friendly but creates triage ambiguity. The best middle ground is plain language, clear boundaries, and predictable response behavior.
If your team is small, start with a minimal policy and version it like code. Clarity that is maintained beats an impressive policy nobody updates.
Troubleshooting: what usually breaks first
1) 404 on /.well-known/security.txt after deploy
Cause: Rewrite rules or missing file at expected path.
Fix: Confirm the file exists on disk, validate Nginx try_files behavior, and reload config safely (nginx -t before reload).
2) Researchers report that email bounced
Cause: Misconfigured mailbox, forwarding loop, or restrictive inbound filtering.
Fix: Test from external mail providers, monitor bounces, and keep a web-form Contact URI as fallback.
3) File is reachable but stale
Cause: Expires not rotated during routine maintenance.
Fix: Add calendar reminders and automate expiry checks in your existing ops scheduler.
4) High spam volume after publishing contact details
Cause: Public mailbox discoverability.
Fix: Use filtering rules, plus a policy URL with scope guidance so low-quality reports decrease over time.
FAQ
Do I need a bug bounty program before publishing security.txt?
No. RFC 9116 is about discoverable reporting channels, not bounty payouts. You can publish clear contact and policy expectations without running a bounty.
Is /security.txt enough, or must I use /.well-known/security.txt?
Use /.well-known/security.txt as primary. A redirect from /security.txt is a practical compatibility fallback, not a substitute for the well-known path.
Should small WordPress sites bother with signatures?
If you already maintain PGP operationally, signing is worth it. If not, prioritize accurate HTTPS hosting, valid contact channels, and fresh Expires values first. Reliability beats half-maintained crypto.
Actionable takeaways you can ship this week
- Publish
/.well-known/security.txtwith at least Contact + Expires today. - Add one email channel and one web policy/reporting URI for resilience.
- Schedule an automated expiry/field check so the file never silently rots.
- Document triage SLAs internally, even if you are a one-person team.
- Review your broader controls quarterly so disclosure workflow and hardening evolve together.
Sources reviewed
- RFC 9116: A File Format to Aid in Security Vulnerability Disclosure
- OWASP Vulnerability Disclosure Cheat Sheet
- WordPress Developer Docs: Hardening WordPress (last modified Jan 7, 2026)
- securitytxt.org implementation guidance
Security work often looks like big controls, expensive tooling, and dramatic incidents. In reality, many incidents are delayed communication failures. security.txt is one of those rare fixes that is small, cheap, and disproportionately useful when the worst day finally arrives.

Leave a Reply