A well-known URI gives software a conventional place to discover information associated with an origin. The reserved /.well-known/ prefix reduces collisions between independently designed protocols, and registered suffixes identify their defining specifications. The prefix is a naming mechanism, not an implementation or a guarantee of trustworthy content. A server must still route the selected endpoint correctly, and a client must interpret the response according to that endpoint’s own contract.

Follow the suffix’s specification

RFC 8615 reserves the namespace for supported URI schemes. It does not require every site to publish every registered resource, and it does not define a common response schema for all suffixes. Consult the IANA registration and its linked specification before deciding the media type, authentication, redirect handling, caching, or transport requirements. A familiar path cannot substitute for these protocol-specific rules.

For web-based vulnerability contact information, RFC 9116 places security.txt at /.well-known/security.txt and requires HTTPS retrieval. A legacy /security.txt location can redirect to the well-known location. The document is UTF-8 plain text with defined fields, including at least one Contact and a single Expires field. Contact gives a reporting channel; it does not prove that a mailbox is staffed or that a submitted report has been accepted.

The document’s Expires field uses a timestamp to limit the age of the information. It is distinct from an HTTP Expires response header. A transport-level 200 does not make stale contact metadata current. Keep the address and policy maintained, and renew the document before it becomes stale. If optional fields such as Canonical or Policy are used, apply their specification rather than treating arbitrary URLs as trusted declarations.

When it breaks

A broad application fallback can return an HTML login page or a site’s home page with status 200 for every unknown path. That looks reachable to a shallow health check but supplies no usable protocol document. Preserve the exact route and inspect both media type and content. An accidental redirect to an unrelated origin can also change the trust context instead of merely moving a file.

The namespace itself authenticates nothing. HTTPS validation establishes the connection to the intended host, while document validation and any additional verification requirements establish whether its contents are usable. Do not infer permission to scan or attack a service from the presence of a security contact. Nor should a deployment blindly expose an entire directory because one standardized resource is intended to be public.

Returning 404 for an unimplemented suffix is different from silently inventing a generic successful document. Each supported endpoint should have an owner and a check suited to its protocol. A registry entry describes a convention; it is not evidence that a particular origin has implemented it or that its current response passed validation.

Check it quickly

Save this as well-known.py and run it with Python 3.14 using python3 well-known.py. The fixture serves only loopback HTTP, with an explicitly fictitious contact at example.invalid. It tests routing and selected document fields. Because it does not use HTTPS, it is not a complete RFC 9116 deployment or a transport-security test.

from datetime import datetime, timedelta, timezone
from http.client import HTTPConnection
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from threading import Thread
import json

now = datetime.now(timezone.utc)
future = (now + timedelta(days=30)).isoformat().replace('+00:00', 'Z')
past = (now - timedelta(days=1)).isoformat().replace('+00:00', 'Z')
content = {'text': f'Contact: mailto:security@example.invalid\nExpires: {future}\n'}


class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        status = 200 if self.path == '/.well-known/security.txt' else 301 if self.path == '/security.txt' else 404
        data = content['text'].encode() if status == 200 else b''
        self.send_response(status)
        if status == 301:
            self.send_header('Location', '/.well-known/security.txt')
        self.send_header('Content-Type', 'text/plain; charset=utf-8')
        self.send_header('Cache-Control', 'no-store')
        self.send_header('Content-Length', str(len(data)))
        self.end_headers()
        self.wfile.write(data)

    def log_message(self, *args):
        pass


def check_contact_and_expiry(text):
    fields = dict(line.split(': ', 1) for line in text.splitlines())
    if not fields.get('Contact', '').startswith('mailto:'):
        raise ValueError('missing demonstration contact')
    expires = datetime.fromisoformat(fields['Expires'])
    if expires <= now:
        raise ValueError('expired metadata')


server = ThreadingHTTPServer(('127.0.0.1', 0), Handler)
thread = Thread(target=server.serve_forever)
thread.start()
try:
    def fetch(path):
        connection = HTTPConnection('127.0.0.1', server.server_port, timeout=5)
        try:
            connection.request('GET', path)
            response = connection.getresponse()
            return {'status': response.status, 'body': response.read().decode(),
                    'location': response.getheader('Location'),
                    'content_type': response.getheader('Content-Type')}
        finally:
            connection.close()

    valid = fetch('/.well-known/security.txt')
    assert valid['status'] == 200 and valid['content_type'] == 'text/plain; charset=utf-8'
    check_contact_and_expiry(valid['body'])
    legacy = fetch('/security.txt')
    assert legacy['status'] == 301 and legacy['location'] == '/.well-known/security.txt'
    assert fetch('/.well-known/unimplemented')['status'] == 404
    rejected = []
    for text in (content['text'].replace(future, past), f'Expires: {future}\n'):
        content['text'] = text
        response = fetch('/.well-known/security.txt')
        assert response['status'] == 200
        try:
            check_contact_and_expiry(response['body'])
        except ValueError as error:
            rejected.append(str(error))
    assert rejected == ['expired metadata', 'missing demonstration contact']
    print(json.dumps({'valid_status': valid['status'], 'legacy_status': legacy['status'],
                      'unimplemented_status': 404, 'rejected_200_documents': rejected,
                      'https_transport_tested': False}))
finally:
    server.shutdown()
    thread.join()
    server.server_close()

The well-known route first returns 200 with the expected plain-text media type, a contact, and expiry thirty days ahead. The legacy path returns 301 to the standard location, and an unimplemented suffix returns 404. The script then serves two invalid documents at the same successful route: one expired and one missing its contact. Both still return HTTP 200 but fail the field checks.

The parser deliberately handles only this known demonstration format. It does not implement all repeated fields, signatures, canonical checks, redirects, or URI validation required by a general consumer. Those limits matter: passing two field checks does not establish full document compliance. Use the experiment to separate location, HTTP success, and usable metadata, then validate the actual protocol requirements before publishing a real endpoint.

Sources