GitHub Packages · MIT · Node ≥ 18

redirect-sentinel

Find open redirects and mixed content in a built site (offline) or a live crawl: http:// scripts and styles on HTTPS pages, insecure forms, client-side redirects fed by the URL, open redirect rules in _redirects/vercel.json/nginx, HTTPS downgrades, and optional safe redirect probing.

  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/redirect-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 redirect-sentinel siteredirect-sentinel — 1 target(s) site  html: 2  js: 1  css: 0  config: 3  HIGH     site/index.html:14  Form submits to http://forms.example.com/submit [insecure-form]           ↳ http://forms.example.com/submit           ↳ fix: Post to https:// only.  HIGH     site/index.html:3  <link rel="stylesheet" href="http://cdn.example.com/style.css"> on an HTTPS page [mixed-content-active]           ↳ http://cdn.example.com/style.css  HIGH     site/index.html:5  <script src="http://cdn.example.com/lib.js"> on an HTTPS page [mixed-content-active]... 12 high, 5 medium, 2 low✖ Failing (fail-on: high).
Real output from running redirect-sentinel locally on a test fixture.

Why it exists

Point redirect-sentinel at your build output (dist/, public/, _site/) in CI, or at a URL to crawl the live site. CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies. Broken links are out of scope (see static-link-sentinel).

Features

Mixed content

on HTTPS pages: http:// scripts, stylesheets, @import, iframes, objects and <base> (active, high); images, srcset, media, icons and CSS url() (passive, medium); forms posting to http://; http:// links (low, once per host). localhost URLs are ignored. Use --http if the static site is not served over HTTPS.

Client-side open redirects

location = …, location.assign/replace, window.open, router.push, navigate fed by location.search/hash, URLSearchParams, document.referrer or window.name, directly or through a variable. Redirects guarded by startsWith('/') or an origin check are skipped. This is a heuristic, not a data-flow engine: minified bundles are only checked for direct flows.

Server redirect rules

Netlify _redirects and netlify.toml, vercel.json/next.config.js, nginx (return 302 $arg_url) and Apache (RewriteRule … %1 [R]) rules whose destination host comes from the request.

Links

that pass a full URL in a redirect-style parameter (next, url, returnTo, redirect_uri, continue, goto…).

Crawl only

redirect chains longer than 3 hops, https:// → http:// downgrades (including meta refresh), http:// not redirecting to https://, and same-origin JavaScript files.

--probe

(crawl only, opt-in): for each same-origin link with a redirect-style parameter, requests it with https://redirect-sentinel.invalid/, //redirect-sentinel.invalid/ and similar payloads, without following the redirect. A Location pointing at that host is a confirmed open-redirect (critical). .invalid can never resolve, so nobody is sent anywhere. Only probe sites you own or are authorised to test.

Usage

# offline, in CI after the build

 npx redirect-sentinel dist/

# Example

 npx redirect-sentinel https://staging.example.com --max-pages 200

# Example

 npx redirect-sentinel https://staging.example.com --probe --fail-on high

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/redirect-sentinel@v1
    with:
      targets: 'dist'
      fail-on: high
      sarif: redirect-sentinel.sarif
  - uses: github/codeql-action/upload-sarif@v3
    if: always()
    with: { sarif_file: redirect-sentinel.sarif }

Options & flags

FlagDescription
--httpStatic pages are served over plain HTTP (skip mixed-content checks)
--max-pages <n>Pages to crawl per URL (default 50)
--max-scripts <n>Same-origin scripts to fetch per URL (default 30)
--probeActively test redirect parameters found while crawling with a harmless
--no-http-checkDo not check that http:// redirects to https://
--timeout <ms>Per-request timeout (default 10000)
Policy and output
-c, --config <file>JSON config (default .redirect-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