# openPDR security intake — RFC 9116 (https://www.rfc-editor.org/rfc/rfc9116). # # Report a suspected vulnerability in the openPDR product, or a security concern # about a managed-tier / demo deployment, to the Contact below. Scope, what to # include, and how a report is handled are in the disclosure policy (Policy # field): # https://openpdr.dev/security # # MAINTENANCE — this is not a fire-and-forget file: # * TWO REPOSITORIES PUBLISH THIS FILE AND THE TWO COPIES MUST STAY # BYTE-IDENTICAL. demo.openpdr.dev serves OpenPDR/openpdr at # deploy/demo/security.txt; openpdr.dev serves OpenPDR/openpdr-site at # public/.well-known/security.txt. Byte-identity is the mechanism, not a # tidiness preference: it is what lets a machine detect drift by comparing, # instead of a human noticing. So EVERY edit below IS AN EDIT TO TWO REPOS. # * Expires is a hard field. Once it passes, a conformant scanner treats the # WHOLE file as invalid, so a published intake channel goes back to reading # as an unpublished one — silently. Renewal is now THREE actions: bump the # date HERE, bump it in the OTHER repo, AND re-confirm that # security@openpdr.dev still reaches a human who will triage a report. # Bumping one repo alone leaves the other host serving an expired file, # which is indistinguishable to a scanner from having no intake at all. # Owner: founder, per SECURITY.md §3. # * THE Policy TARGET IS A PAGE IN THE OTHER REPO, NOT A FILE HERE. # https://openpdr.dev/security is served from OpenPDR/openpdr-site. It is # a purpose-written public page, NOT a copy of SECURITY.md: SECURITY.md # stays the internal full version and links private docs/compliance/* # paths that 404 for the anonymous reporter this field exists for, which # is why it is no longer the Policy target (#457). Renaming or deleting # that page re-breaks this line from a repo this one cannot see, and no # check here can notice. # * BOTH Canonical URLs are listed on purpose, in both copies. RFC 9116 # §2.5.2 tells a consumer not to trust a file fetched from a URI that the # file's own Canonical does not name — so a per-host copy naming only its # own host would publish an intake channel that conformant tooling is # instructed to distrust, which is worse than publishing none. Canonical # may repeat; Expires and Preferred-Languages may not. # * CI enforces the mechanical half and nothing can enforce that a human # answers. In OpenPDR/openpdr: check-security-txt.sh fails once Expires has # passed and warns for the 60 days before it (test.yml on every push, # drills.yml weekly so the calendar alone can trip it); # check-security-txt-routing.sh proves this file is really served at the # Canonical URL, and that no other path under /.well-known/ reaches the # file server (deploy/demo/Caddyfile); deploy.sh refuses to deploy if # Canonical does not name the host it is deploying to; deploy-demo.yml then # fetches the live URL. In OpenPDR/openpdr-site: deploy.yml asserts this # file is in the set Firebase would actually upload BEFORE deploying (a # dot-directory is one firebase.json "ignore" edit away from vanishing # from that set with the deploy still green), fetches the live apex URL # after, and diffs this copy against the file SERVED at the other # Canonical URL — so the two hosts drifting apart turns the run red. # * No PGP key is published deliberately — report over authenticated TLS email; # add an Encryption field here only once a key is actually generated and held. Contact: mailto:security@openpdr.dev Expires: 2027-08-01T00:00:00.000Z Preferred-Languages: en Canonical: https://demo.openpdr.dev/.well-known/security.txt Canonical: https://openpdr.dev/.well-known/security.txt Policy: https://openpdr.dev/security