GitHub Packages · MIT · Node ≥ 18

securitytxt-sentinel

Validate security.txt (RFC 9116) and robots.txt for your domains, or as local files in CI before you deploy them.

  1. 1 Point the @mrlouiswright scope at GitHub Packages in .npmrc

    @mrlouiswright:registry=https://npm.pkg.github.com
  2. 2 Install

    npm i -D @mrlouiswright/securitytxt-sentinel
Installing from GitHub Packages needs a token

Published to GitHub Packages, not npmjs.com. GitHub Packages needs a GitHub token with read:packages to install, even for public packages: add //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} to .npmrc or run npm login --registry=https://npm.pkg.github.com.

~/project — zsh
$ npx securitytxt-sentinel bad-security.txtsecuritytxt-sentinel — 1 target(s) bad-security.txt  kind: security.txt  HIGH     bad-security.txt:3  Expired on 2025-01-01T00:00:00Z (652 days ago): clients should treat the file as stale [expired]           ↳ 2025-01-01T00:00:00Z           ↳ fix: Review the contacts and set a new Expires date.  MEDIUM   bad-security.txt:4  Expires appears 2 times (it must appear at most once) [duplicate-field]  MEDIUM   bad-security.txt:2  Contact uses http:// (http://example.com/report) [insecure-uri]           ↳ http://example.com/report           ↳ fix: Use https://.  MEDIUM   bad-security.txt:1  Contact "security@example.com" is not a mailto:, tel: or https: URI [invalid-contact]           ↳ security@example.com... 1 high, 4 medium, 2 low, 2 info✖ Failing (fail-on: high).
Real output from running securitytxt-sentinel locally on a test fixture.

Why it exists

securitytxt-sentinel fetches /.well-known/security.txt (falling back to the legacy /security.txt) and /robots.txt for each domain and checks them against RFC 9116 and common robots.txt mistakes. It catches the classic failure: a security.txt whose Expires passed months ago, so researchers are told to ignore it. Local files can be linted too, so a broken security.txt never ships. CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies.

Features

security.txt

present at the right location, served over HTTPS as text/plain; charset=utf-8, not an HTML soft-404, redirects that leave the host, required Contact and Expires, Expires that is invalid, expired, about to expire (--warn-days, default 30) or more than a year ahead, duplicate fields, Contact values that are not mailto:/tel:/https: URIs, http:// URIs, Canonical missing or not matching the fetched URL, bad Preferred-Languages tags, malformed PGP cleartext signatures, unknown fields and invalid lines.

robots.txt

missing file, HTML soft-404, invalid directives, rules before any User-agent, sitemaps that are relative or http://, files over Google's 500 KiB limit, Disallow: / for everyone, and Disallow lines that advertise sensitive areas (/admin, /backup, /.git, /phpmyadmin…). robots.txt is public and is not access control.

missing

No security.txt at /.well-known/security.txt (default: high)

soft-404

security.txt URL returns HTML or an error page instead of the file (default: high)

not-https

security.txt is not served over HTTPS (default: high)

missing-contact

No Contact field (required) (default: high)

missing-expires

No Expires field (required) (default: high)

expired

Expires date is in the past (default: high)

Usage

# Example

 npx securitytxt-sentinel example.com www.example.org

# Example

 npx securitytxt-sentinel example.com --no-robots --warn-days 60 --fail-on medium

# Example

 npx securitytxt-sentinel public/.well-known/security.txt --canonical https://example.com/.well-known/security.txt

# Example

 npx securitytxt-sentinel public/robots.txt

CI / GitHub Action

permissions:
  contents: read
  security-events: write   # only for the SARIF upload
steps:
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
    with: { persist-credentials: false }
  - uses: MrLouisWright/securitytxt-sentinel@v1
    with:
      targets: 'example.com'
      fail-on: high
      sarif: securitytxt-sentinel.sarif
  - uses: github/codeql-action/upload-sarif@v3
    if: always()
    with: { sarif_file: securitytxt-sentinel.sarif }

Options & flags

FlagDescription
--no-robotsSkip robots.txt
--kind <k>Treat local files as "security" or "robots"
--canonical <url>Expected Canonical URL when linting a local security.txt
--warn-days <n>Warn when Expires is closer than this (default 30)
--timeout <ms>Per-request timeout (default 10000)
Policy and output
-c, --config <file>JSON config (default .securitytxt-sentinel.json if present)
-f, --format <fmt>text (default) | json | sarif | markdown
--json/--sarif/--markdown <file>Also write that format to a file
--fail-on <sev>critical | high | medium | low | info | none (default high)
--list-rulesPrint rules and default severities
--no-colorDisable colours

Full reference, config file format and API in the README.

Support this project

Support open-source security tools

I build free, open-source tools that help developers ship safer websites. Every coffee helps keep them maintained, documented and free for everyone.

Buy me a coffee (opens Stripe in a new tab)

Secure checkout by Stripe

Portrait of Louis Wright

About the author

Louis Wright

Cyber security researcher and software engineer based in the UK.

More tools by Louis Wright

58 tools

Sentinels security scanners & CI gates · 19