Setting up CI/CD Security with GuardianX
Shift security left: wire GuardianX into GitHub Actions, GitLab CI, and Jenkins. Scan every PR, block merges on Critical findings, and post inline code comments.
Shifting security left — running scans on every pull request instead of waiting for a pre-release VAPT — reduces remediation cost by 10-100x. This tutorial shows how to wire GuardianX into your CI/CD pipeline so every PR is automatically scanned, with findings posted as inline code comments and Critical issues blocking merges.
Why CI/CD Security?
A vulnerability caught in development costs minutes to fix. The same vulnerability caught in production costs hours (incident response, hotfix deploy, customer comms). CI/CD scanning catches issues at the cheapest possible point in the lifecycle.
Prerequisites
- A GuardianX account (any tier)
- A repository on GitHub, GitLab, or Bitbucket
- CI/CD runner: GitHub Actions, GitLab CI, or Jenkins
- GuardianX API token (Settings → API Tokens → Generate)
Option 1: GitHub Actions
Add this workflow to .github/workflows/guardianx.yml:
yamlname: GuardianX Security Scan on: pull_request: branches: [main, develop] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install GuardianX CLI run: | curl -fsSL https://guardianx.cloud/install.sh | sh - name: Run SAST scan env: GUARDIANX_TOKEN: ${{ secrets.GUARDIANX_TOKEN }} run: | guardianx scan sast \ --path . \ --format json \ --output findings.json \ --fail-on critical - name: Post inline comments if: always() env: GUARDIANX_TOKEN: ${{ secrets.GUARDIANX_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | guardianx comment github \ --findings findings.json \ --pr ${{ github.event.pull_request.number }}
Add GUARDIANX_TOKEN as a repository secret (Settings → Secrets → Actions).
Option 2: GitLab CI
Add to .gitlab-ci.yml:
yamlguardianx-sast: image: node:20 stage: test only: - merge_requests script: - curl -fsSL https://guardianx.cloud/install.sh | sh - guardianx scan sast --path . --format json --output findings.json --fail-on critical - guardianx comment gitlab --findings findings.json --mr $CI_MERGE_REQUEST_IID artifacts: reports: sast: findings.json
Set GUARDIANX_TOKEN as a CI/CD variable (Settings → CI/CD → Variables).
Option 3: Jenkins
Add a Jenkinsfile stage:
groovypipeline { agent any stages { stage('GuardianX SAST') { steps { sh 'curl -fsSL https://guardianx.cloud/install.sh | sh' withCredentials([string(credentialsId: 'guardianx-token', variable: 'TOKEN')]) { sh ''' guardianx scan sast \ --path . \ --format json \ --output findings.json \ --fail-on critical \ --token $TOKEN ''' } } } } }
Configuration: fail-on Thresholds
GuardianX CLI supports several thresholds:
--fail-on critical— exit code 1 if any Critical finding--fail-on high— exit 1 if any Critical OR High--fail-on medium— exit 1 if Medium or above--fail-on low— exit 1 on any finding (strict)
Recommended: start with --fail-on critical for the first month, then escalate to --fail-on high once the team is comfortable.
Inline Code Comments
The CLI's comment subcommand posts findings as PR review comments on the exact line of code. Developers see them in their IDE without leaving GitHub. Each comment includes:
- Severity badge
- Vulnerability class (e.g., "SQL Injection")
- Why it's vulnerable
- Suggested patch (AI-generated, copy-pasteable)
Baseline: Ignoring Pre-existing Findings
If your codebase has 200 existing findings and you don't want to block every PR, use the baseline feature:
bash# Initial baseline guardianx baseline create --path . --output baseline.json # Subsequent scans ignore findings present in baseline guardianx scan sast --path . --baseline baseline.json --fail-on critical
New findings introduced in a PR will block; pre-existing ones won't.
DAST in CI/CD
For dynamic scanning, deploy your PR branch to a staging environment, then run:
bashguardianx scan dast \ --url https://pr-${PR_NUMBER}.staging.acme.com \ --format json \ --output dast-findings.json \ --fail-on high
DAST scans take longer (2-10 min), so consider running them only on PRs touching specific paths (e.g., /api/).
Secrets Scanning
GuardianX also scans for hardcoded secrets (AWS keys, DB passwords, JWT secrets, Stripe keys):
bashguardianx scan secrets --path . --fail-on any
Recommend: --fail-on any for secrets scanning — there's no acceptable number of leaked secrets.
Status Checks
After configuring the workflow, add GuardianX as a required status check in your branch protection rules (GitHub: Settings → Branches → Edit → Require status checks to pass before merging → select "GuardianX Security Scan").
Notifications
Wire findings to Slack:
bashguardianx notify slack \ --findings findings.json \ --webhook ${{ secrets.SLACK_WEBHOOK }} \ --severity high
Performance Tips
- Cache the GuardianX binary in CI to avoid re-downloading
- Run SAST only on changed files with
--diffflag for large repos - Parallelize SAST + DAST + secrets scans as separate jobs
- Use a self-hosted runner for very large monorepos
Measuring DevSecOps Success
Track these metrics over time:
- MTTR (mean time to remediate) — should drop
- Critical findings per 1k LOC — should trend toward 0
- % of PRs blocked by GuardianX — should be <5% after baseline
- Time to first finding — should be <30 seconds
A mature CI/CD security pipeline catches 95%+ of vulnerabilities before merge, with zero developer friction. Sign up for GuardianX and try it on your repo today.
Sign up for GuardianX
Run a full SAST + DAST + patch-generation VAPT scan on your codebase in under 5 minutes. No credit card required.