GitHub Packages · MIT · Node ≥ 18

dns-sentinel

Audit your domains' DNS and email security before attackers or spammers find the gaps.

DNS and email security auditor: SPF (10-lookup limit, +all, ptr), DMARC, DKIM key strength, MX/null MX, MTA-STS, TLS-RPT, CAA, DNSSEC via DoH, dangling CNAME and subdomain takeover, wildcards and AXFR, with a fix for each. Text, JSON, SARIF, Markdown; GitHub Action. Zero deps.

  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/dns-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 dns-sentinel example.comdns-sentinel — 1 domain(s) · resolver: DoH https://cloudflare-dns.com/dns-query; DNSSEC: DoH https://cloudflare-dns.com/dns-query louiswright.co.uk  MX: 30 athena.hosts.co.uk, 30 hermes.hosts.co.uk  SPF: v=spf1 include:stspg-customer.com include:spf.hosts.co.uk include:_spf.firebasemail.com ~all (7 lookups)  DMARC: v=DMARC1; p=none;  DKIM: no keys found  MTA-STS: none  TLS-RPT: none  CAA: none  DNSSEC: off  Wildcard: CNAME s.multiscreensite.com  www.louiswright.co.uk: CNAME → cname.vercel-dns.com... 2 medium, 6 low, 1 info✔ Passing (fail-on: high).
Sample output from the dns-sentinel README.

Why it exists

dns-sentinel checks SPF, DMARC, DKIM, MX / null MX, MTA-STS, TLS-RPT, CAA and DNSSEC. It also finds dangling CNAMEs and subdomain takeovers, wildcard records and open zone transfers. Every finding comes with a severity and a concrete fix, usually the exact DNS record to publish.

CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies. Lookups use “node:dns/promises” (system or chosen resolvers) by default. DNS-over-HTTPS is optional, and the DNSSEC check uses it by default to read the validating resolver's AD flag.

Features

SPF

spf-missing (high; medium for non-mail domains), spf-multiple (high), spf-too-many-lookups (high; nested includes, a, mx, exists, redirect counted against the 10-lookup limit), spf-void-lookups (medium), spf-pass-all (critical, +all), spf-neutral-all (medium, ?all), spf-no-all (medium), spf-ptr (medium, including via includes), spf-invalid (syntax errors, include targets without SPF, include loops, terms after all), spf-softfail-all (info)

DMARC

dmarc-missing (high), dmarc-multiple (high), dmarc-invalid (high), dmarc-policy-none (medium; high for non-mail domains), dmarc-no-rua (low), dmarc-pct (medium, pct < 100), dmarc-weak-subdomain (medium, sp weaker than p). Subdomains fall back to the organisational domain's record and its sp

DKIM

Selectors from --dkim-selector, plus ~30 common selectors with --dkim-common. dkim-weak-key (critical for RSA < 1024 bits, medium for < 2048), dkim-revoked (low, empty p=), dkim-testing (low, t=y), dkim-missing (medium), dkim-invalid (medium), dkim-not-found (low)

MX

mx-missing (recommends a null MX MX 0 . for domains that don't receive mail), null-mx-misconfigured (high), null-mx-spf (medium), mx-dangling (high), mx-cname (low), mx-ip-literal (medium)

MTA-STS / TLS-RPT

mta-sts-missing (low), mta-sts-invalid (medium: TXT id, policy fetch over HTTPS, policy syntax), mta-sts-testing (low), mta-sts-mx-mismatch (medium; high in enforce mode), tlsrpt-missing (low), tlsrpt-invalid (low)

CAA

Closest-ancestor lookup (RFC 8659). caa-missing (low), caa-permissive (low; no issue tags or > 3 CAs), caa-critical-unknown (high), caa-no-iodef (info)

DNSSEC

DS and DNSKEY presence plus the AD flag from a validating DoH resolver. dnssec-disabled (medium), dnssec-no-ds (medium), dnssec-broken (high: SERVFAIL, or DS without validation), dnssec-weak-algorithm (RSASHA1/DSA keys, SHA-1-only DS)

Dangling CNAMEs

For --subdomain, --subdomains-file or --common-subdomains: follows the CNAME chain and flags dangling-cname (high: target NXDOMAIN; medium: no addresses). subdomain-takeover (critical) when the target is a takeover-prone service and either doesn't exist or serves the service's "unclaimed" page (HTTP fingerprint). takeover-prone-cname (info) otherwise. Services include AWS S3 and Elastic Beanstalk, GitHub Pages, Heroku, Azure (App Service, Cloud Services, Traffic Manager, Blob, CDN, Front Door…), Shopify, Fastly, Pantheon, Tumblr, Ghost, Surge, Bitbucket, Netlify, Webflow, Zendesk, ReadMe, Unbounce, Help Scout, Strikingly, Fly.io, Agile CRM, Canny, Statuspage, WordPress.com and Google Cloud Storage

Usage

# Example

 npx dns-sentinel example.com

# Example

 npx dns-sentinel example.com example.org --dkim-selector google,s1 -s www -s docs -s status

# Example

 npx dns-sentinel example.com --subdomains-file subdomains.txt --fail-on medium -f sarif > dns.sarif

# all lookups over DNS-over-HTTPS (Cloudflare)

 npx dns-sentinel example.com --doh

CI / GitHub Action

on:
  schedule: [{ cron: '0 6 * * 1' }]
permissions:
  contents: read
jobs:
  dns:
    runs-on: ubuntu-latest
    steps:
      - uses: MrLouisWright/dns-sentinel@<sha> # v1
        with:
          domains: example.com example.org
          subdomains: www docs status
          dkim-selectors: google,s1
          fail-on: medium

Options & flags

FlagDescription
--checks <list>Comma-separated: spf, dmarc, dkim, mx, mta-sts, tls-rpt, caa, dnssec, cname, wildcard, axfr
--skip <list>Checks to skip
--dkim-selector <s>DKIM selector to test (repeatable or comma-separated)
--dkim-commonAlso try ~30 common DKIM selectors
-s, --subdomain <name>Subdomain to test for dangling/takeover CNAMEs (repeatable; "www" or "www.example.com")
--subdomains-file <f>File with subdomains, one per line
--common-subdomainsAlso test ~40 common subdomain names
--axfrAttempt a zone transfer against each nameserver (off by default)
--no-httpDo not fetch MTA-STS policies or takeover fingerprints over HTTP
Resolver
--doh [url]Use DNS-over-HTTPS for all lookups (default https://cloudflare-dns.com/dns-query)
--dnssec-doh <url>DoH endpoint for the DNSSEC/AD check (default Cloudflare)
--no-dnssec-dohCheck DNSSEC with plain DNS to --resolver instead of DoH
--timeout <ms>Per-lookup timeout (default 5000)
Policy and output
-c, --config <file>JSON config (default .dns-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 (default) | medium | low | info | none
--list-rulesPrint rules and default severities

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