GitHub Action
The Pwnkemon Scan GitHub Action runs a full code scan on every pull request, posts findings as a PR comment, and fails the build when something serious is found. It is published at github.com/Pwnkemon/pwnkemon-scan.
How it's different
The Action is deliberately not a wrapper that runs scanners on your GitHub runner. It triggers a scan in an isolated, ephemeral container on Pwnkemon's infrastructure and waits for the result. That has three concrete consequences:
- Your CI secrets never see scanner code. The runner only ever holds your Pwnkemon API token. The repo source is cloned on our side, not yours.
- You don't pay CI minutes for scanning. A standard scan takes ~30 seconds of GitHub-runner time regardless of repo size — the runner makes one HTTP call, then polls. The actual scan (osv-scanner, semgrep, trivy, gitleaks, npm-audit, LLM triage) runs on dedicated infra.
- Findings are triaged, not dumped. Every other CI scanner produces a wall of unreachable transitive-dep noise and asks you to triage it. Pwnkemon's LLM does the triage server-side before findings ever reach your PR — so a “high” in the comment is one you actually need to look at.
Quick start
- Install the Pwnkemon GitHub App on the repos you want to scan. (If you haven't already, do it via Targets in the dashboard.)
- Mint a GitHub Action token at /dashboard/tokens → “GitHub Action tokens” → Create. These tokens are narrowly scoped: they can launch scans and read results, and nothing else — they cannot mint other tokens, touch billing, or change your account. See API tokens for the full scope model.
- Add it as a repo secret named
PWNKEMON_API_TOKEN(Settings → Secrets and variables → Actions → New repository secret). - Drop the workflow file into your repo at
.github/workflows/pwnkemon.yml:
name: Pwnkemon Security Scan
on:
pull_request:
workflow_dispatch: {}
permissions:
contents: read
pull-requests: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: Pwnkemon/pwnkemon-scan@v1
with:
api-token: ${{ secrets.PWNKEMON_API_TOKEN }}That's it. Open a PR; the Action posts a findings table as a PR comment, edits it in place on subsequent commits, and fails the build if anything at high severity or above lands.
Inputs
| Name | Default | Description |
|---|---|---|
api-token | — | Required. Pwnkemon API token (pt_action_* kind). Store in repo secrets. |
tier | standard | Scan depth. quick (1 credit, fastest); standard (full LLM triage); deep (10 credits, exhaustive). Allowed tiers depend on your plan — see Pricing. |
fail-on | high | Severity floor that fails the workflow run. One of: critical, high, medium, low, none. Default high means criticals + highs fail the build; lower-severity findings report but don't block. |
comment-pr | true | Post (or update in-place) a comment on the PR with the findings table. Requires pull-requests: write in the workflow permissions block. |
comment-on-clean | true | When the scan finds nothing, still post a “no findings” confirmation comment. Set to false to stay silent on clean runs. |
wait-for-completion | true | Block the workflow until the scan finishes. Set to false to launch async and let the workflow continue immediately (useful when you don't want scans to gate deploys). |
timeout-minutes | 30 | Max wait time before the Action gives up on a running scan. |
github-token | ${{ github.token }} | Token used for the PR comment. Defaults to the workflow's own — only override for cross-repo / app setups. |
Outputs
| Name | Description |
|---|---|
scan-id | Pwnkemon scan UUID — pass to other steps for cross-reference. |
report-url | Direct link to the full report in the Pwnkemon dashboard. |
finding-count | Total number of confirmed (post-triage) findings. |
status | Final scan status: completed, failed, cancelled, timeout, or queued (when wait-for-completion: false). |
Common configurations
Block deploys only on criticals
- uses: Pwnkemon/pwnkemon-scan@v1
with:
api-token: ${{ secrets.PWNKEMON_API_TOKEN }}
fail-on: criticalAsync on push to main, blocking on PRs
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: Pwnkemon/pwnkemon-scan@v1
with:
api-token: ${{ secrets.PWNKEMON_API_TOKEN }}
wait-for-completion: ${{ github.event_name == 'pull_request' }}Deep scan on releases, standard everywhere else
- uses: Pwnkemon/pwnkemon-scan@v1
with:
api-token: ${{ secrets.PWNKEMON_API_TOKEN }}
tier: ${{ github.event_name == 'release' && 'deep' || 'standard' }}What gets scanned
Every commit you trigger the Action on is scanned at that exact commit, not whatever the branch has advanced to by the time the scan starts. We clone the branch, then git checkout the SHA from your CI context — so a scan posted to PR #42 always reflects the code in PR #42, even if main races ahead.
The scan itself runs the same pipeline as a dashboard-launched code scan: see Code scans for the full scanner list, triage behaviour, and reachability classification.
Security model
The token (pt_action_*) is restricted server-side to:
- Launch a scan against your verified repos
- Read the resulting scan's status and findings
Nothing else. A leaked Action token cannot mint other tokens, read your billing, change your plan, delete data, or impersonate you in the dashboard. It can spend your credits launching scans (you can rate-limit + revoke), and it can read findings on scans the token itself launched. That's the blast radius.
On the scanner side, every PR scan runs in a fresh docker run --rm container that holds no long-lived secrets, sees only the cloned repo + a short-lived GitHub installation token for the clone, and is destroyed on exit. See Security & privacy for the full execution-isolation model.
Troubleshooting
Error: Input required and not supplied: api-token— thePWNKEMON_API_TOKENsecret isn't set on the repo, or the secret name in your workflow doesn't match. Names are case-sensitive; the secret must live under Repository secrets (not Environment secrets, unless your workflow names the environment).401 Invalid API token— the token is wrong, expired, or revoked. Mint a fresh one at /dashboard/tokens.402 Insufficient credits— your credit balance is too low for the requested tier. Upgrade your plan or pick a cheaper tier.403on launch — the Pwnkemon GitHub App isn't installed on this repo. Add it at github.com/settings/installations.- No PR comment appears — your workflow probably doesn't grant
pull-requests: write. Addpermissions: { pull-requests: write }at the workflow level.
Source
The Action's source is open at github.com/Pwnkemon/pwnkemon-scan — MIT licensed. ~250 lines of TypeScript. Most of what it does is in this page; the rest is bookkeeping. Security teams who require review-before-adoption can read the bundle that runs in their CI directly.