The GitHub Actions Security Scan Workflow Builder generates a CI workflow that scans both your code and your dependencies on every change. It wires up CodeQL static analysis for code vulnerabilities, an npm audit step for known dependency advisories, and an optional Snyk scan, triggered on pushes to main, on pull requests, and on a weekly schedule.
The three scanning layers and what each catches
CodeQL (static code analysis)
CodeQL is GitHub’s semantic code analysis engine. Unlike linters that check syntax and style, CodeQL treats your code as data — it builds a queryable database of your codebase and runs security queries against it to find patterns like:
- SQL injection and XSS in web applications
- Path traversal vulnerabilities
- Insecure deserialization
- Use of unsafe APIs (e.g.
eval,dangerouslySetInnerHTML) - Authentication bypass patterns
Results appear in the repository’s Security → Code scanning tab with line-level annotations. CodeQL runs free on public repositories; private repositories require GitHub Advanced Security.
npm audit (dependency vulnerabilities)
npm audit compares your package-lock.json against the npm advisory database and flags packages with known CVEs. The workflow runs it with a severity threshold (--audit-level=high by default) so the job fails only for serious advisories, not every low-severity warning in deep transitive dependencies. This catches the class of vulnerability that affects your users even if your own code is clean — a compromised or vulnerable dependency in your supply chain.
Snyk (optional, deeper dependency scanning)
Snyk provides a more detailed dependency analysis than npm audit, with fix suggestions and a broader vulnerability database. It requires a free Snyk account and a SNYK_TOKEN added as a repository secret. It also scans Docker images and IaC (Terraform, Kubernetes) if you use those.
How the workflow is structured
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # Weekly Monday 06:00 UTC
permissions:
security-events: write
contents: read
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v3
with:
languages: javascript
- uses: github/codeql-action/autobuild@v3
- uses: github/codeql-action/analyze@v3
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm audit --audit-level=high
Why a scheduled weekly scan?
Your code may not change for weeks, but new vulnerabilities are disclosed against dependencies you already use. A weekly cron scan (schedule trigger) catches these newly disclosed advisories without waiting for the next code change to trigger CI. It’s also the only way to catch vulnerabilities that are disclosed after a PR merges but before the next code push.
Practical setup tips
security-events: writeis required. Without this permission, CodeQL’sanalyzestep cannot upload results to the Security tab. The builder adds it automatically.- Start the audit threshold at
high. Transitive dependencies often carry low-severity advisories that are not exploitable in your context. Start athigh(or evencritical) and tighten once you’ve resolved the serious ones. - Add
SNYK_TOKENbefore enabling Snyk. Without the token, the Snyk step fails with an authentication error on every run — add the secret first. - CodeQL’s
autobuildmay need help. For compiled languages (Java, C++),autobuildruns heuristics to build the code. If it fails, replace it with your actual build command. For JavaScript/TypeScript, autobuild is usually not needed. - Review findings, don’t just dismiss them. CodeQL findings are ranked by severity. Even a “medium” finding deserves a read — some are exploitable, and dismissing them without review defeats the purpose of running the scan.