//CI & CLI

Catch it in review, not in production.

The repository scanner runs on your machine or in your pipeline. It reads your filesystem and sends us nothing, findings come back with file and line, and the exit code fails the build.

runs onGitHub ActionsGitHub ActionsGitLabGitLabNodeNodeBunBun

From your terminal

Scans committed credentials, env-file handling, unsafe migrations and unprotected route handlers.

bash
npx flare-deep .                    # scan the current directory
npx flare-deep . --fail-on high     # stricter threshold
npx flare-deep . --json out.json    # machine-readable output
npx flare-deep . --sarif flare.sarif # SARIF for GitHub Code Scanning

In GitHub Actions

.github/workflows/security.yml
name: Security
on:
  pull_request:
  push:
  schedule:
    - cron: "0 7 * * *"   # daily, because risk changes without you

jobs:
  flare:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx flare-deep . --fail-on critical
        # exits non-zero on a critical finding → the build fails

The schedule line is the one people leave out, and it is the one that catches the class of problem you cannot cause. Your lockfile does not change, and then an advisory is published against a package you already depend on, yesterday’s clean run is wrong this morning, with no commit and no deploy to tell you. Commit-triggered scanning cannot see that by definition. A daily run re-checks the same lockfile against the advisory database and fails the moment the answer changes.

Findings on the exact line, in GitHub’s Security tab

Add --sarif and upload the result, and every finding shows up as an annotation on the exact line in the pull request and in your repo’s Security → Code scanning tab — the same place GitHub’s own tools report. Paste this in and you’re done:

.github/workflows/flare-code-scanning.yml
name: Flare
on: [pull_request, push]

permissions:
  contents: read
  security-events: write   # lets the results appear in the Security tab

jobs:
  flare:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx flare-deep . --sarif flare.sarif --fail-on critical
      - if: always()   # upload even when the build fails, so you still see why
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: flare.sarif

The commit and branch are picked up automatically, so GitHub attaches each finding to the right place. Not sure what any of this means? Hand this whole page to whoever set up your project — it’s a two-minute job for them.

A summary on the pull request

The scan also posts a single comment on the PR (worst findings first, each with its file and line and the fix) and edits that same comment on every push rather than stacking a new one. It states what was found and stops: no severity theatre, no invented stakes. The blocking gate is the exit code above; this is the part a reviewer reads.

ts
# generate the comment body
npx flare-deep . --pr-comment flare-comment.md --fail-on low
# then post it with actions/github-script (contents: read, pull-requests: write)

Exit codes

0Nothing at or above the threshold. The build continues.
1At least one finding at or above --fail-on. The build fails.
2The scan itself errored. Treat as inconclusive, not as a pass.

Suppressing a finding

Test fixtures and documentation sometimes have to contain credential-shaped text. Mark the line rather than excluding whole files, so the suppression stays visible in review:

ts
const key = "sk_live_EXAMPLEKEYFORTESTS"; // flare-ignore: fixture

Nothing leaves your machine

The repo scanner reads your filesystem locally. No upload, no account.

Git-aware

It asks git what's tracked before calling anything committed, and skips ignored files entirely.

Or drive it from an agent

The MCP server exposes the same scan as a tool your editor can call.

Start with the external scan.

See what’s exposed from the outside first, then wire the repo scan in.

Run your free scan