// DevOps

Security.txt: A mailbox for bug reports you forgot about

Published on 2026-03-30

Imagine: an ethical hacker finds an exposed .env file or a critical vulnerability on your server. They don’t want to hack you — they want to help. They go to the site, look for contacts and… hit a wall. The feedback form requires an “order number”, the chat bot asks to “choose a question category”, and the support phone line is busy.

In the end the researcher either drops it (and the hole remains), or publishes it publicly, creating a reputation crisis for you out of nowhere.

To avoid this, the standard RFC 9116 was adopted — the security.txt file. It’s a simple way to officially tell the world: “If you found a problem, write here, we’ll listen.”


What’s inside?

The file should be located at /.well-known/security.txt. It’s a UTF-8 text format where each line is a separate directive.

  • Contact (required): A link to an email or form. It’s important to use the URI format. Multiple contacts are allowed.
    • Contact: mailto:security@example.com
    • Contact: https://example.com/security-form
  • Expires (required): The file’s expiration date. By the standard, the data should not be considered valid forever. It’s recommended to update it once a year. ISO 8601 format (for example, 2027-01-01T00:00:00Z).
  • Encryption: A link to your public PGP key. It’s good practice to provide a way to encrypt the report so vulnerability details are not intercepted in transit.
  • Preferred-Languages: A list of languages your team prefers to read reports in (for example, ru, en).
  • Acknowledgments: A link to a “Hall of Fame” page. A small thing that greatly motivates researchers — a simple public “thank you” for a found bug.
  • Policy: Perhaps the most important field. It’s a link to your Vulnerability Disclosure Policy (VDP).

Vulnerability Disclosure Policy (VDP): How not to scare people

The Policy field leads to a page where you describe the rules of the game. The main mistake here is turning the page into a dry legal document that forbids everything.

A good policy should answer three questions:

1. What can be tested? (Scope)

If the scope is unclear — the researcher will either not contact you or will take risks. Clearly specify domains: example.com, api.example.com. Explicitly exclude what must not be touched: staging.example.com, admin panels, or third-party integrations (Stripe, Cloudflare).

2. What is forbidden? (Rules of Engagement)

Set boundaries. At a minimum this should prohibit:

  • DoS / DDoS attacks.
  • Social engineering against employees.
  • Accessing or deleting other people’s data.

3. What do you promise in return? (Safe Harbor)

This is a key trust element. You should explicitly state: “We will not initiate legal action if you act within this policy and responsibly disclose the vulnerability.”

Tip: Write in human language. The phrase “We appreciate your contribution and commit to responding to reports within 48 hours” works much better than a ten-page liability waiver.


Tool: securitytxt.org

Manually formatting dates in ISO 8601 or checking syntax is a waste of time. There’s a service for that: securitytxt.org.

It’s an extremely simple generator: you fill in fields, the service validates them against the standard and produces the ready text. You can also prepare a Cleartext Signature there to guarantee the file’s authenticity.


Technical implementation

Creating the file is half the job. The server must serve it with correct headers.

Caddy configuration

In Caddy you can serve the file directly from the config:

example.com {
    handle_path /.well-known/security.txt {
        header Content-Type "text/plain; charset=utf-8"
        respond "Contact: mailto:security@example.com
Expires: 2027-03-30T10:00:00Z
Policy: https://example.com/security-policy
Preferred-Languages: ru, en"
    }
}

Automation with Ansible

If you have a fleet of a dozen servers, it’s easiest to deploy this file with a single task:

- name: Ensure .well-known directory exists
  file:
    path: /var/www/html/.well-known
    state: directory
    mode: '0755'

- name: Deploy security.txt to all web nodes
  copy:
    dest: /var/www/html/.well-known/security.txt
    content: |
      Contact: mailto:security@example.com
      Expires: 2027-12-31T23:59:59Z
      Policy: https://example.com/security-policy
      Preferred-Languages: ru, en
    mode: '0644'

Conclusion

Security.txt is not “protection against hacking.” It’s insurance against learning about a critical hole last. Setting it up takes 10 minutes, but it shifts your relationship with the security community from “enemies and intruders” to “partners.”

This is a best practice for any serious project in 2026.

// Reviews

Related reviews

// Contact

Need help?

Get in touch with me and I'll help solve the problem