Fail a deploy that exposes something

Run the same read-only scan as this site against every deployment, and fail the job when it finds a leaked key, a table anyone can read, a private file being served, or anything else at or above the severity you choose. It needs no token, no checkout of your code and no account, and nothing is sent to xlogs: the scan runs on your CI runner.

After each deployment (Vercel, Netlify and others)

Hosting providers that report deployments to GitHub fire a deployment_status event with the deployed URL. This workflow scans each successful one and uploads the findings to the repository's Security tab.

name: Security
on: deployment_status

permissions:
  security-events: write   # only for the SARIF upload; the scan needs none

jobs:
  xlogs:
    # deployment_status also fires for pending and failed deployments
    if: github.event.deployment_status.state == 'success'
    runs-on: ubuntu-latest
    steps:
      - uses: damnepic/xlogs-cli@v0.2.4
        with:
          url: ${{ github.event.deployment_status.environment_url || github.event.deployment_status.target_url }}
          fail-on: high
          sarif: xlogs.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()   # upload the findings even when the gate failed
        with:
          sarif_file: xlogs.sarif

If your preview deployments sit behind a login (Vercel Deployment Protection, for example), the scanner reads the login page, not your app. The gate then fails with exit 4 instead of passing an app it never saw. Scan your production URL instead, on a schedule or after a production deploy.

On a schedule

name: Nightly security check
on:
  schedule:
    - cron: "0 6 * * *"
  workflow_dispatch:

permissions: {}

jobs:
  xlogs:
    runs-on: ubuntu-latest
    steps:
      - uses: damnepic/xlogs-cli@v0.2.4
        with:
          url: https://your-app.com
          fail-on: high

Inputs

InputDefaultWhat it does
urlrequiredThe deployed URL to scan.
fail-onhighFail the job on a finding at or above this severity: critical, high, medium or low.
allow-inconclusivefalsePass even when a check could not run. Every check that did not run is still named in the log.
sarifnoneA path to write a SARIF 2.1.0 report to, for the repository's Security tab.

The URL reaches the scanner as an environment variable, never pasted into a shell command, so an event payload cannot become code. There is deliberately no stack-only input: a gate that skipped the private-file and database checks would pass by not looking.

What the job sees

Exit codeMeaning
0Nothing at or above fail-on. The job passes.
1A finding at or above fail-on. The job fails and the log names each one.
3The input was unusable, or the URL could not be reached. The job fails.
4Nothing found at or above fail-on, but a check could not run, so the gate cannot call it a pass. The job fails unless allow-inconclusive is true.

The most common exit 4: hosted Supabase stopped letting a public key list a project's tables in April 2026, so the database check cannot run on many Supabase apps. A gate that could not test your database has not passed it. Set allow-inconclusive: true to accept that explicitly; the log still names every check that did not run.

Any other CI

The action is a thin wrapper. Any runner with Node 18.18 or newer and git can run the same release directly:

npx -y github:damnepic/xlogs-cli#v0.2.4 https://your-app.com --fail-on high

What it sends

Every request is a GET. The full list, including the files that must never be public and the anonymous database read, is on the methodology page. Run the gate against your own deployment only. To let your coding agent run the same scan while it works, see xlogs for MCP.