Scans GitHub Actions YAML files for 225 vulnerabilities, attack paths, and security anti-patterns in under 10 seconds.
This is a GitLab Component port of gha-exploit-guard. Includes the most up-to-date real-world attacks and defenses.
- Requirements
- GitLab Component Usage
- CLI Usage
- SARIF and Security Dashboard
- Local Testing
- Maintainer Branch Protection Policy
- GitLab 15.0 or later — required for SARIF support in
artifacts:reports:sast. - GitLab 16.6 or later — required for
spec.inputs.regexvalidation on component inputs. On older versions, input constraints are silently ignored. - GitLab 17.0 or later — required if using CI/CD Component inclusion (
include: component:). For older GitLab versions, useinclude: project:instead (see examples below).
Include the template in your .gitlab-ci.yml using include: project::
include:
- project: 'your-org/exploit-guard-for-gitlab'
ref: main # pin to a commit SHA or tag for production
file: '/templates/exploit-guard.yml'The template defines an exploit-guard-scan job that clones this repository, installs dependencies, runs the scanner against your project, and uploads SARIF results.
Important: When using
include: project:, thespec.inputsregex validations and default values do not apply. You must set allEXPLOIT_GUARD_*variables explicitly. For full input validation, useinclude: component:on GitLab 17.0+.
Override defaults using CI/CD variables:
include:
- project: 'your-org/exploit-guard-for-gitlab'
ref: main # pin to a commit SHA or tag for production
file: '/templates/exploit-guard.yml'
exploit-guard-scan:
variables:
EXPLOIT_GUARD_TARGET_DIR: '.'
EXPLOIT_GUARD_FAIL_ON_FINDINGS: 'true'
EXPLOIT_GUARD_EXCLUDE: 'EG085,EG042'On GitLab 17.0+, you can also use CI/CD Component syntax:
include:
- component: gitlab.com/your-org/exploit-guard-for-gitlab/exploit-guard@main
inputs:
exploit-guard-project: 'your-org/exploit-guard-for-gitlab'
target-dir: '.'
fail-on-findings: 'true'Security: For production pipelines, pin the
ref(or component@ref) to a specific commit SHA or tag rather thanmainto prevent supply-chain attacks via branch compromise.
When using include: component:, pass these as component inputs:
| Input | Default | Description |
|---|---|---|
target-dir |
. |
Directory to scan, relative to project root |
fail-on-findings |
false |
Fail the job when scanner reports findings |
exclude |
(empty) | Comma-separated check IDs to skip (e.g. EG001,EG035) |
warn-only |
false |
Report findings without failing the job |
sarif-file |
exploit-guards.sarif |
SARIF output file path |
image |
python:3 |
Docker image (must have bash, python3, pip, and git) |
exploit-guard-project |
(required) | GitLab project path of this repo (e.g. your-org/exploit-guard-for-gitlab) |
exploit-guard-ref |
main |
Git ref of the exploit-guard repo to use |
When using include: project:, set these as CI/CD variables prefixed with EXPLOIT_GUARD_:
| Variable | Default | Maps to |
|---|---|---|
EXPLOIT_GUARD_TARGET_DIR |
. |
target-dir |
EXPLOIT_GUARD_FAIL_ON_FINDINGS |
false |
fail-on-findings |
EXPLOIT_GUARD_EXCLUDE |
(empty) | exclude |
EXPLOIT_GUARD_WARN_ONLY |
false |
warn-only |
EXPLOIT_GUARD_SARIF |
exploit-guards.sarif |
sarif-file |
bash(version 4.0 or later) must be available onPATH.python3(version 3.11 or later) withpipmust be available. PyYAML is installed automatically viapip installin the default image.gitmust be available (the component clones this repo at runtime).opensslmust be available onPATH(used for clone integrity verification in the component template).- Works on any GitLab Runner with Docker or shell executor.
Tip: For production, pin the
imageinput to a SHA digest (e.g.python:3@sha256:abc...) to prevent supply-chain attacks via mutable Docker tags.
The component uses CI_JOB_TOKEN to clone the exploit-guard repo. The token needs read access to the exploit-guard-project repository. If the scanner repo is in a different group/project:
- In the scanner repo settings: go to Settings > CI/CD > Token Access and add the consumer project to the allowlist.
- The consumer's
CI_JOB_TOKENonly needsread_repositoryscope on the scanner project — no write access is required.
Keep token permissions minimal to reduce blast radius if a runner is compromised.
gha-exploit-guard.sh /path/to/github-actions/repo/
gha-exploit-guard.sh .
gha-exploit-guard.sh --warn-only
gha-exploit-guard.sh --exclude EG085,EG042
gha-exploit-guard.sh --helpUse --exclude with a comma-separated list of check IDs to skip specific checks:
gha-exploit-guard.sh . --exclude EG085,EG042Invalid IDs produce a warning but do not block the scan.
Add a YAML comment to any workflow file to suppress specific checks for that file only:
# exploit-guard-disable: EG085
# exploit-guard-disable: EG085,EG042
name: my-workflow
on: pushWhen a file contains an inline suppression comment, the scanner returns empty content for that file during the suppressed check, effectively skipping it.
The scanner produces two output files:
exploit-guards.txt— human-readable text outputexploit-guards.sarif— machine-readable SARIF 2.1.0 JSON
When using the GitLab Component, the SARIF file is automatically uploaded as a SAST artifact. Findings appear in:
- The Security Dashboard (project and group level)
- The Merge Request security widget
- The Vulnerability Report
Note: SARIF support in
artifacts:reports:sastrequires GitLab 15.0 or later.
The scanner produces SARIF 2.1.0 output with fields required by GitLab's SAST report ingestion:
runs[].tool.driver.name,runs[].tool.driver.rules[],results[].level, andresults[].locations[].physicalLocation. GitLab silently drops findings that lack these fields.
Exit code semantics:
0: all checks passed1: one or more checks failed (findings)>1: scanner/runtime failure
Note: When
warn-onlyis enabled, the job exits 0 but SARIF findings are still reported at"level": "error". GitLab's Security Dashboard will display them as vulnerabilities regardless of the exit code.
CLI users can generate SARIF with --sarif FILE:
gha-exploit-guard.sh /path/to/repo --sarif exploit-guards.sarifFrom repo root:
bash ./gha-exploit-guard.sh --help# expected final status: 0 or 1; 2 indicates runtime/test harness failure
./tests/test-workflow-exploit-guards.sh .# static contract checks for script wiring
./tests/test-offline.sh# list and filter available checks
./tests/test-offline.sh --list
./tests/test-workflow-exploit-guards.sh --list
./tests/test-workflow-exploit-guards.sh --filter fixture --junit test-results.xmlConfigure in GitLab project settings under Settings > Repository > Protected branches:
- Protect the default branch (
main). - Set Allowed to merge to Maintainers.
- Set Allowed to push and merge to No one (enforce merge requests).
- Require at least one approval in Settings > Merge requests > Approval rules.
- Require these CI jobs to pass before merge:
regressionintegration