Security Scanning

Learn how to integrate GitLab's security scanners into your CI/CD pipelines. From static analysis to container scanning, build a DevSecOps workflow that catches vulnerabilities before they reach production.

SAST DAST Dependency Secret Container
Why Security Scanning in CI/CD?

Security vulnerabilities found in production are expensive. They require emergency patches, incident response, and sometimes public disclosure. The longer a vulnerability exists in your codebase, the higher the chance it gets exploited. Security scanning in CI/CD shifts this detection left — catching issues during development, in merge requests, before code is merged and deployed. This is the core idea of DevSecOps: make security an integral part of the development workflow rather than a separate gate at the end.

GitLab provides a suite of security scanners that integrate directly into your pipelines. Each scanner targets a different layer of the application: SAST analyzes source code for vulnerabilities like SQL injection, DAST tests the running application for runtime issues, Dependency Scanning checks your libraries for known CVEs, Secret Detection finds accidentally committed credentials, and Container Scanning inspects Docker images for vulnerable OS packages [citation:1][citation:15]. Together, they provide defense in depth across the software supply chain.

These scanners are enabled by including GitLab's official CI/CD templates. A single include line activates a scanner, which then runs automatically on every pipeline (subject to rules). Results appear in merge requests, the security dashboard, and the vulnerability report, making findings actionable without leaving GitLab. For teams on Ultimate, findings can also block merges via security approvals, creating a true security gate [citation:1].

Core Principle: Each scanner covers a different attack surface. SAST finds code flaws, DAST finds runtime flaws, dependency scanning finds supply chain flaws, secret detection finds leaked credentials, and container scanning finds infrastructure flaws. You need all of them.

SAST

Static analysis of source code. Finds SQL injection, XSS, hardcoded secrets in code. Runs during build/test stage.

DAST

Dynamic analysis of running application. Crawls and attacks staging environment. Finds runtime vulnerabilities.

Dependency Scanning

Checks lockfiles (package-lock.json, go.sum, etc.) for known CVEs in dependencies. Runs on every commit.

Secret Detection

Scans commits and history for API keys, tokens, passwords. Prevents credential leaks before they become breaches.

Container Scanning

Scans Docker image layers for vulnerable OS packages. Runs after image is built and pushed.

Security Dashboard

Aggregates findings across projects. Tracks vulnerability trends and remediation progress. Ultimate tier.
SAST: Static Application Security Testing

SAST analyzes your source code without running it, looking for patterns that indicate security vulnerabilities. GitLab's SAST is powered by multiple analyzers — Semgrep for pattern-based checks across many languages, NodeJsScan for Node.js-specific issues, and KubeSec for Kubernetes manifests [citation:11]. The scanner automatically detects your project's languages and runs the appropriate analyzers, producing a JSON report that GitLab parses and displays in merge requests.

Enabling SAST is a single include line. The template creates jobs that run in the test stage, scan the code, and upload the results. By default, SAST jobs have allow_failure: true, meaning findings won't block the pipeline. For production pipelines, you can set allow_failure: false or configure security approvals to require review before merging when high-severity findings exist [citation:1].

SAST results appear directly in merge requests, showing exactly which lines of code triggered a finding. For Ultimate users, GitLab can even suggest fixes — a "Resolve with AI" or "Resolve with merge request" button generates a patch that addresses the vulnerability [citation:1]. This closes the loop from detection to remediation without leaving the MR.

# Enable SAST include: - template: Security/SAST.gitlab-ci.yml stages: - build - test - deploy # SAST runs automatically in test stage # No additional configuration required for basic scanning # Customize SAST (exclude paths, disable analyzers) sast: variables: SAST_EXCLUDED_PATHS: "spec, test, tests, tmp" SAST_EXCLUDED_ANALYZERS: "nodejs-scan" SCAN_KUBERNETES_MANIFESTS: "true" # Custom ruleset (Ultimate) sast: variables: SAST_RULESET_PATH: ".gitlab/sast/ruleset.toml" # Fail pipeline on findings (use with caution) sast: allow_failure: false # Available SAST variables: # SAST_EXCLUDED_PATHS - Paths to exclude from scanning # SAST_EXCLUDED_ANALYZERS - Analyzers to skip # SCAN_KUBERNETES_MANIFESTS - Enable KubeSec scanning # SAST_RULESET_PATH - Custom ruleset file # Results: # - gl-sast-report.json artifact # - Findings in MR security widget # - Vulnerability report in Security > Vulnerability Report # - Security dashboard (Ultimate)
SAST Best Practices:
  • Exclude test directories and generated code to reduce noise
  • Run SAST on every commit and merge request
  • Use security approvals for critical findings (Ultimate)
  • Review SAST findings in MRs before merging
  • Customize rulesets to match your organization's policies
DAST: Dynamic Application Security Testing

DAST tests your application while it's running, simulating attacks against a deployed environment. Unlike SAST, which analyzes code statically, DAST interacts with the live application — crawling pages, submitting forms, and probing for vulnerabilities like cross-site scripting, SQL injection, and misconfigured headers. This catches issues that only manifest at runtime, such as authentication bypasses or server misconfigurations [citation:2].

GitLab's DAST uses a browser-based crawler (Chromium) to discover pages and test them. You must provide a target URL via DAST_TARGET_URL or an environment_url.txt file. If your application requires login, you configure authentication with DAST_AUTH_USERNAME, DAST_AUTH_PASSWORD, and field selectors. Without authentication, DAST can only scan publicly accessible pages, missing the majority of your application [citation:2][citation:17].

DAST is most effective against a staging environment that mirrors production. Running it against production is risky (active scanning could cause issues) and running it against localhost requires the runner to have network access. The typical pattern is: deploy to staging, run DAST against staging, then deploy to production after DAST passes. Results appear in the vulnerability report and can be configured to block deployments or require approvals [citation:7].

# Enable DAST include: - template: Security/DAST.gitlab-ci.yml stages: - build - test - deploy - dast # Basic DAST configuration dast: stage: dast variables: DAST_TARGET_URL: "https://staging.example.com" DAST_FULL_SCAN: "false" # Quick scan for MRs rules: - if: $CI_COMMIT_BRANCH == "main" # DAST with authentication dast: stage: dast variables: DAST_TARGET_URL: "https://staging.example.com" DAST_AUTH_URL: "https://staging.example.com/login" DAST_AUTH_USERNAME: "testuser" DAST_AUTH_PASSWORD: $DAST_PASSWORD # From CI/CD variables DAST_AUTH_USERNAME_FIELD: "css:input[name=username]" DAST_AUTH_PASSWORD_FIELD: "css:input[name=password]" DAST_AUTH_SUBMIT_FIELD: "css:button[type=submit]" # Full scan on schedule, quick scan on MRs dast: stage: dast variables: DAST_TARGET_URL: "https://staging.example.com" DAST_FULL_SCAN: "true" DAST_CRAWL_GRAPH: "true" # Generate crawl graph rules: - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_BRANCH == "main" variables: DAST_FULL_SCAN: "false" # DAST with environment_url.txt (dynamic environments) # In deploy job: deploy_staging: stage: deploy script: - ./deploy.sh staging - echo "https://staging.example.com" > environment_url.txt artifacts: paths: - environment_url.txt # Available DAST variables: # DAST_TARGET_URL - Target URL (required) # DAST_FULL_SCAN - true/false (full vs quick scan) # DAST_AUTH_URL - Login page URL # DAST_AUTH_USERNAME/PASSWORD - Credentials # DAST_AUTH_USERNAME_FIELD/PASSWORD_FIELD - Form selectors # DAST_CRAWL_GRAPH - Generate crawl graph (for debugging) # DAST_SCOPE_EXCLUDE_ELEMENTS - Elements to exclude from crawl
DAST Caveats: