GitHub Action
Run Flowpatrol security scans on every pull request with a single workflow file.
Every PR gets a security check. No extra steps for your team — just push code, and Flowpatrol posts findings as a comment. Set severity gates to block merges when something critical shows up.
Quick start
Add your API key as a secret
Go to your repo's Settings > Secrets and variables > Actions. Add a new secret:
- Name:
FLOWPATROL_API_KEY - Value: your API key (starts with
fp_live_)
Don't have a key yet? Create one in the dashboard.
Add the workflow file
Create .github/workflows/flowpatrol.yml in your repo:
name: Security Scan
on:
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: flowpatrol/scan-action@v1
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
mode: probeThat's it. Push this file, open a PR, and Flowpatrol will post results as a comment.
Full configuration
Here's every input the action accepts:
- uses: flowpatrol/scan-action@v1
with:
# Required
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
# Scan mode: probe (1 credit), standard (5 credits), deep (8 credits)
mode: probe # default: probe
# Fail the check if findings meet this severity threshold
fail-on: high # default: none (never fail)
# Post findings as a PR comment
comment: true # default: true
# Upload SARIF to GitHub Code Scanning
sarif: false # default: false
# Wait for scan to complete before continuing
wait: true # default: true
# Timeout in minutes (applies when wait is true)
timeout: 15 # default: 10Inputs
| Input | Required | Default | Description |
|---|---|---|---|
api-key | Yes | — | Your Flowpatrol API key |
target | Yes | — | URL to scan (must be reachable from GitHub Actions runners) |
mode | No | probe | Scan mode: probe, standard, or deep |
fail-on | No | none | Fail if findings at this severity or above: critical, high, medium, low, none |
comment | No | true | Post a PR comment with findings |
sarif | No | false | Upload SARIF to GitHub Code Scanning |
wait | No | true | Wait for the scan to finish |
timeout | No | 10 | Max wait time in minutes |
Outputs
| Output | Description |
|---|---|
scan-id | The unique scan identifier |
status | Scan status: complete, running, failed |
findings-count | Total number of findings |
critical-count | Number of critical findings |
high-count | Number of high findings |
medium-count | Number of medium findings |
low-count | Number of low findings |
report-url | Direct link to the scan report in the Flowpatrol dashboard |
sarif-file | Path to the SARIF file (when sarif: true) |
Use outputs in subsequent steps:
steps:
- uses: flowpatrol/scan-action@v1
id: scan
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
- run: echo "Found ${{ steps.scan.outputs.findings-count }} issues"PR comments
When comment: true (the default), Flowpatrol posts a summary comment on the PR:
## Flowpatrol Security Scan
**Target:** https://myapp.vercel.app
**Mode:** Probe | **Duration:** 12s
| Severity | Count |
|----------|-------|
| Critical | 0 |
| High | 2 |
| Medium | 1 |
| Low | 1 |
### Findings
- **HIGH** Supabase anon key in JS bundle — `/static/js/main.a3f2c.js`
- **HIGH** RLS disabled on "profiles" table — PostgREST API
- **MEDIUM** Missing Content-Security-Policy header — `/`
- **LOW** X-Powered-By header exposes framework — `/`
[View full report](https://app.flowpatrol.ai/scans/abc123)The action updates the same comment on subsequent pushes to the PR — no duplicate comments cluttering your timeline.
SARIF integration
SARIF lets findings show up in GitHub's Security tab alongside CodeQL and Dependabot alerts. Enable it with the sarif input and add an upload step:
steps:
- uses: flowpatrol/scan-action@v1
id: scan
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
mode: standard
sarif: true
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: ${{ steps.scan.outputs.sarif-file }}SARIF upload requires GitHub Advanced Security or a public repository. The if: always() ensures the SARIF file is uploaded even when fail-on causes the scan step to fail.
Severity gating
Use fail-on to block PRs when findings meet a severity threshold. The action exits with code 1 when any finding matches or exceeds the threshold.
fail-on value | Fails when there are... |
|---|---|
critical | Critical findings |
high | High or Critical findings |
medium | Medium, High, or Critical findings |
low | Any findings at all |
none | Never fails (default) |
Pair this with branch protection rules — require the Flowpatrol check to pass before merging:
fail-on: high # Block the PR if anything high or critical is foundScan modes and credits
| Mode | Credits | Time | Best for |
|---|---|---|---|
probe | 1 | ~10s | Every PR — fast, cheap, catches surface issues |
standard | 5 | 2-5 min | Pre-release — tests auth, access control, injection |
deep | 8 | 10-30 min | Nightly or weekly — multi-user IDOR, chained attacks |
Probes run on every PR. Save standard and deep scans for merges to main or scheduled runs to manage credit usage.
Examples
Probe on every PR
The most common setup. Fast, cheap, catches obvious issues before review:
name: Security Probe
on:
pull_request:
branches: [main]
jobs:
probe:
runs-on: ubuntu-latest
steps:
- uses: flowpatrol/scan-action@v1
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
mode: probe
fail-on: highStandard scan on merge to main
Run a deeper scan after code lands on main. Good for catching auth and access control issues:
name: Security Scan (Main)
on:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: flowpatrol/scan-action@v1
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
mode: standard
fail-on: critical
sarif: true
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: ${{ steps.scan.outputs.sarif-file }}Nightly deep scan
Schedule a deep scan for exhaustive coverage without burning credits on every push:
name: Nightly Deep Scan
on:
schedule:
- cron: '0 3 * * *' # 3 AM UTC daily
jobs:
deep-scan:
runs-on: ubuntu-latest
steps:
- uses: flowpatrol/scan-action@v1
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: https://myapp.vercel.app
mode: deep
timeout: 30Dynamic target from Vercel preview
Scan the actual preview deployment instead of a hardcoded URL:
name: Scan Preview
on:
deployment_status:
jobs:
scan:
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- uses: flowpatrol/scan-action@v1
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: ${{ github.event.deployment_status.target_url }}
mode: probe
fail-on: highMonorepo matrix
Scan multiple apps in a single workflow:
name: Security Scan (Monorepo)
on:
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
strategy:
matrix:
app:
- { name: "web", url: "https://web.myapp.com" }
- { name: "api", url: "https://api.myapp.com" }
- { name: "admin", url: "https://admin.myapp.com" }
steps:
- uses: flowpatrol/scan-action@v1
with:
api-key: ${{ secrets.FLOWPATROL_API_KEY }}
target: ${{ matrix.app.url }}
mode: probe
fail-on: highTroubleshooting
Target not reachable
GitHub Actions runners need to reach your target URL over the public internet. If your app is behind a firewall or VPN, use the CLI from a machine with access instead.
Scan times out
Increase the timeout value. Standard scans typically finish in under 5 minutes, but larger apps can take longer. Deep scans can take up to 30 minutes.
Comment not appearing
The action needs pull-requests: write permission. If you're using a custom permissions block, add it explicitly:
permissions:
pull-requests: write
security-events: write # Only needed if using sarif: trueSARIF upload fails
SARIF upload requires either a public repo or GitHub Advanced Security. Check that security-events: write is in your permissions block.