How to Add Security Testing to Your CI/CD Pipeline (Without Slowing Down Deploys)

The number one objection to adding security testing in CI/CD is speed. Engineering teams that deploy ten times a day are not going to wait 30 minutes for a full vulnerability scan on every push. They should not have to.

Here is how to add meaningful security testing to your pipeline without turning your deploys into a bottleneck.

The two-tier approach

Split your security testing into two categories: fast checks that run on every commit, and deep scans that run on a schedule or before releases.

Tier 1: Pipeline checks (under 2 minutes). These run on every PR or merge request. They cover configuration issues, known CVEs in dependencies, secret detection, and a lightweight DAST pass against critical endpoints. The goal is catching regressions and obvious mistakes before they reach staging.

Tier 2: Scheduled deep scans (15-45 minutes). These run nightly or before each release. Full DAST crawl, authenticated testing, API fuzzing, and compliance checks. Results feed into your dashboard and ticketing system.

GitHub Actions setup

Add the SecTests action to your workflow file. The --quick flag runs Tier 1 checks:

- name: Security scan
  uses: sectests/action@v2
  with:
    target: ${{ secrets.STAGING_URL }}
    api-key: ${{ secrets.SECTESTS_API_KEY }}
    mode: quick
    fail-on: critical

The action pulls a lightweight Docker image, runs the scan against your staging environment, and posts results as a PR comment. If a critical finding is detected, the check fails and the merge is blocked.

GitLab CI setup

Add a security stage to your .gitlab-ci.yml. The scanner runs in a Docker container:

security_scan:
  stage: test
  image: sectests/scanner:latest
  script:
    - sectests scan --target $STAGING_URL --mode quick --fail-on critical
  artifacts:
    reports:
      junit: sectests-results.xml

The JUnit XML output integrates with GitLab's test reporting UI. Security findings appear alongside your unit test results.

Jenkins setup

Install the SecTests Jenkins plugin from the plugin marketplace. Add a build step with your target URL and API key. The plugin supports both freestyle and pipeline jobs. For pipeline scripts, use the sectests step:

stage('Security') {
  steps {
    sectests target: env.STAGING_URL, mode: 'quick', failOn: 'critical'
  }
}

What to fail on

This is the question every team debates. Our recommendation:

  • Pipeline checks (Tier 1): Fail on critical findings only. High-severity findings generate warnings but do not block. This keeps deploys moving while catching genuinely dangerous issues.
  • Release scans (Tier 2): Fail on critical and high findings. These run less frequently, so the team has time to investigate and remediate before the next release.

Avoid failing on medium or low findings in CI. It trains developers to ignore security checks or find workarounds. Start strict on critical issues and expand the threshold as your team matures.

Performance impact

Tier 1 scans with the --quick flag typically complete in 45 to 90 seconds. They run in parallel with your other CI steps, so the added wall-clock time is often zero if your test suite takes longer than that.

If even that is too slow, use the --diff flag to scan only endpoints that changed in the current commit. This reduces scan time to 10-20 seconds on most PRs.

Security testing in CI/CD is not about finding every vulnerability on every commit. It is about establishing a baseline, catching regressions, and making sure the obvious problems never reach production. Start with Tier 1 on your next PR.