This record and format is for website and infrastructure operators to implement opt-outs and/or verifications for scanning services and designate reporting and notification endpoints.
_scan.{domain}{scanner domain}.{root record}| code | applicability | description | 
|---|---|---|
| v | required | Version, set to “SCAN1” | 
| sr | required in scsd ignored in root | Source scanner - must match the scanner subdomain | 
| p | optional in scsd ignored in root | Policy - “opt-out” or “none”, default is “none” | 
| sp | optional in scsd ignored in root | Subdomain Policy - “opt-out” or “none”, default is “none” | 
| ruh | optional | Reporting URI(s) for humans | 
| rua | optional | Reporting URI(s) for aggregate scan statistics or results | 
| ruf | optional | Reporting URI(s) for detailed scan results | 
| rue | optional in scsd ignored in root | Report URIs encrypted; used scanner public key to encrypt ruh/rua/ruf- “yes” or “no”, default is “no” | 
| ri | optional | Reporting interval for aggregate reports | 
| rf | optional | Report format for ruaandruf- “jwt” or “json”, default is “json” | 
| vf | optional in scsd | Verification, a hash or other alphanumeric value for scanners to verify ownership | 
| al | optional | Alternative domain hint, an FQDN to potentially scan as well or instead, where another scantxt lookup is required | 
| nb | optional | A timestamp from when the record applies - rfc3339 format | 
| ex | optional | An expiry timestamp when the record no longer applies - rfc3339 format | 
| rq | optional | Require scanning signature - “yes” or “no”, default is “no” | 
| es | optional | Expected signature attibute | 
Human report URI (ruh) can be either:
mailto:...@...https://example.com/contactAggregate (rua) or details (rud) can be either:
report-to:https://...mailto:...@...Requiring scanning signatures is only currently recommended on HTTP(S) only scanners. If rq=yes then any scanning without an X-Scanning-Token (or field set with es) should be dropped.
Expected signature attribute specifies what the target will be checking (format type:field, for example http_header:X-ST).
Simple report example:
_scan 3600 TXT "v=SCAN1; ruh=mailto:security@example.com;"
Time-based verification example for a pentest:
pentest-company.example.com._scan 3600 TXT "v=SCAN1; vf=abc123; sr=pentest-company.example.com; nbd=2022-12-22T23:45:00Z; exp=2023-01-22T23:45:00Z;"
Complex example:
| subdomain | TXT record | 
|---|---|
| _scan | v=SCAN1; ruh=https://example.com/contact,mailto:security@example.com; | 
| _scan.mail | v=SCAN1; ruh=mailto:post@example.com; | 
| _scan.servers | v=SCAN1; ruh=mailto:infra@example.com; ruf=report-to:https://infra-report-to.example.com; | 
| scanner.example.com._scan | v=SCAN1; rq=yes; es=http_header:scanner-token; sr=scanner.example.com; | 
| scantxt.app._scan | v=SCAN1; p=opt-out; sp=opt-out; | 
Simple:
[
  {
    "v": "SCAN1",
    "ruh": "https://example.com/.well-known/security.txt"
  }
]
Multiple Scanners:
[
  {
    "v": "SCAN1",
    "ruh": "https://example.com/.well-known/security.txt"
  },
  {
    "v": "SCAN1",
    "sr": "scanner.example.com",
    "rq": "yes"
  },
  {
    "v": "SCAN1",
    "sr": "scantxt.app",
    "p": "opt-out",
    "sp": "opt-out"
  }
]