GitLab’s Static Application Security Testing (SAST) feature is designed to scan your source code for security vulnerabilities before you deploy, a concept often referred to as "shifting left" in security.

Let’s see it in action. Imagine you have a simple Python Flask application and you’ve added a requirements.txt file:

Flask==2.2.2
requests==2.28.1

You also have a .gitlab-ci.yml file. To enable SAST, you just need to add a stage for it and include the template:

stages:
  - build
  - test
  - sast # Add this stage

include:
  - template: Security/SAST.gitlab-ci.yml

build_app:
  stage: build
  script:
    - echo "Building the app..."
    - pip install -r requirements.txt

run_tests:
  stage: test
  script:
    - echo "Running unit tests..."
    - python -m unittest discover

When this pipeline runs, GitLab automatically detects the presence of the SAST.gitlab-ci.yml template and injects its own jobs. One of these jobs, gemnasium-python in this case, will execute. It analyzes your dependencies and code for known vulnerabilities.

Here’s what the gemnasium-python job might look like internally (you don’t need to configure this, GitLab handles it):

# This is an example of what GitLab injects, not something you write
gemnasium-python:
  stage: .pre # SAST jobs run early
  image: registry.gitlab.com/security-products/gemnasium-python:2
  variables:
    GIT_STRATEGY: none # No need to clone the repo for dependency scanning
  script:
    - /gemnasium-python scan --output "$SAST_REPORT_FILE"
  artifacts:
    reports:
      sast: "$SAST_REPORT_FILE"
  allow_failure: true # SAST failures won't block the pipeline by default

The gemnasium-python tool, running within its dedicated Docker image, takes your project’s context. It first identifies the package manager (pip, in this case) and then analyzes the requirements.txt file. It cross-references the detected dependencies (Flask 2.2.2, requests 2.28.1) against its internal vulnerability database. If it finds any known CVEs associated with these specific versions, it reports them. The results are then formatted into a sast.json artifact, which GitLab displays in the Merge Request or Pipeline Security tab.

The core problem SAST solves is the late discovery of security flaws. Traditionally, security audits happened late in the development cycle, making fixes expensive and time-consuming. By integrating SAST into CI, you get immediate feedback on potential vulnerabilities as code is committed and merged. This allows developers to address issues while the code is still fresh in their minds, significantly reducing remediation costs and improving overall application security.

GitLab’s SAST capabilities are not limited to just dependency scanning. It supports multiple languages and frameworks, using various analyzers like Semgrep, Bandit, and others depending on the detected language. For example, if you had Python code with potential security anti-patterns (like using eval() insecurely), Bandit would be invoked to detect those.

The power lies in the configuration, or rather, the lack of it for basic setup. GitLab’s Auto DevOps and built-in SAST templates abstract away much of the complexity. You typically enable it by including the template. For more advanced scenarios, you can customize which analyzers run, specify paths to exclude, or even provide custom rulesets. The SAST_EXCLUDE_ANALYZER variable is useful here; for instance, SAST_EXCLUDE_ANALYZER: "semgrep" would disable the Semgrep analyzer if you found its output noisy for your project.

GitLab SAST doesn’t just find vulnerabilities; it provides context. For each finding, it typically offers a description of the vulnerability, its severity, a CWE (Common Weakness Enumeration) identifier, and often a remediation advice. This makes it actionable for developers.

One aspect that often surprises people is how SAST analyzers determine the "confidence" of a finding. It’s not just about matching a known CVE. Tools like Semgrep use abstract syntax tree (AST) analysis and pattern matching to identify potentially insecure code constructs even if they haven’t been officially cataloged as a CVE for that specific version. This means SAST can sometimes flag novel or "zero-day-like" vulnerabilities, or simply insecure coding practices that deviate from best practices, even if no public exploit exists yet. The confidence level helps you triage these, distinguishing between a high-confidence match to a known exploit and a lower-confidence heuristic-based warning.

After you’ve addressed all the SAST findings, the next security-related pipeline job you’ll likely encounter is Dependency Scanning, which focuses on vulnerabilities in your project’s dependencies.

Want structured learning?

Take the full Gitlab-ci course →