GitLab Security Scanning
GitLab can automatically scan your code, dependencies, containers, and infrastructure for security vulnerabilities every time a pipeline runs. It catches problems before they reach production — without requiring a separate security tool.
Why Automated Security Scanning Matters
Traditional security process: ───────────────────────────────────────────────────── Code written → shipped to production → security team audits weeks later → vulnerabilities found → costly fix GitLab security scanning: ───────────────────────────────────────────────────── Code written → pipeline runs → vulnerabilities flagged in merge request → developer fixes before merge ✅
Finding a bug after release costs up to 15 times more to fix than catching it during development.
The Five Main Scan Types
| Scan Type | What It Checks | Example Finding |
|---|---|---|
| SAST | Your source code for logic flaws | SQL injection in login function |
| Dependency Scanning | Third-party libraries for known CVEs | lodash 4.17.11 has a prototype pollution bug |
| Container Scanning | Docker images for OS-level vulnerabilities | OpenSSL 1.1.0 in base image has critical CVE |
| DAST | Running app from the outside like a hacker | Missing security headers on login page |
| Secret Detection | Code for accidentally committed secrets | AWS access key found in config.js |
SAST — Static Application Security Testing
SAST reads your source code without running it and looks for patterns that commonly lead to security vulnerabilities. It works like a spell checker but for security flaws.
Code GitLab SAST flags:
──────────────────────────────────────────────────────────
❌ query = "SELECT * FROM users WHERE id = " + userId
Problem: SQL Injection — attacker can manipulate userId
✅ query = "SELECT * FROM users WHERE id = ?"
parameters = [userId]
Safe: parameterized query prevents injection
──────────────────────────────────────────────────────────
Enabling SAST
Add the SAST template to your .gitlab-ci.yml:
include:
- template: Security/SAST.gitlab-ci.yml
stages:
- test
# SAST jobs are added automatically by the template
GitLab detects your programming language and picks the right analyser automatically (Semgrep for Python/JavaScript, SpotBugs for Java, Brakeman for Ruby on Rails, etc.).
Dependency Scanning
Your project likely uses dozens of open-source libraries. Each library can carry known vulnerabilities catalogued in public databases (CVEs). Dependency scanning checks your package.json, requirements.txt, pom.xml, and other lock files against these databases.
include:
- template: Security/Dependency-Scanning.gitlab-ci.yml
Scan result example: ────────────────────────────────────────────────────────── Vulnerability: CVE-2023-26115 Package: word-wrap 1.2.3 Severity: High Fix: Upgrade to word-wrap 1.2.4 ──────────────────────────────────────────────────────────
Secret Detection
Developers sometimes accidentally commit API keys, passwords, or tokens directly into code. Secret Detection scans every commit — including the full git history — for these patterns.
include:
- template: Security/Secret-Detection.gitlab-ci.yml
Finding example: ────────────────────────────────────────────────────────── File: config/database.js Line 12 Type: AWS Access Key Severity: Critical Value: AKIA•••••••••••••••• (masked in display) Action: Revoke key immediately and rotate it ──────────────────────────────────────────────────────────
If a secret is found, revoke it immediately even if you delete the commit. Git history is visible to anyone with repository access, and the secret may already have been seen.
Container Scanning
Docker base images contain an operating system and dozens of pre-installed packages. Any of these packages can have unpatched vulnerabilities. Container scanning inspects the layers of your built image.
include:
- template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
CS_IMAGE: registry.gitlab.com/acme/my-webapp:latest
Scan result: ────────────────────────────────────────────────────────────────── Base image: node:18-alpine Finding: CVE-2023-38545 zlib 1.2.11 Severity: Critical Fix: Update base image to node:20-alpine (zlib patched) ──────────────────────────────────────────────────────────────────
DAST — Dynamic Application Security Testing
DAST runs your application and probes it from the outside, sending crafted requests to find weaknesses that only appear at runtime.
DAST process:
─────────────────────────────────────────────────────
App deployed to review environment
↓
DAST scanner sends hundreds of test requests
(like an automated hacker probing your app)
↓
Reports: missing headers, open redirects,
XSS vulnerabilities, insecure cookies
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: https://staging.myapp.com
The Security Dashboard
All scan results aggregate in one place: Secure → Vulnerability Report. Every vulnerability shows:
- Severity (Critical, High, Medium, Low, Info)
- The scanner that found it
- The affected file, line, or package
- A description and recommended fix
- Status (Detected, Confirmed, Dismissed, Resolved)
Vulnerability Report ────────────────────────────────────────────────────────────────── Severity Name Scanner Status ────────────────────────────────────────────────────────────────── Critical AWS key in config.js Secret Det. Detected High SQL Injection — login.py SAST Confirmed High CVE-2023-26115 word-wrap Dep. Scan Resolved ✅ Medium Missing X-Frame-Options DAST Dismissed ──────────────────────────────────────────────────────────────────
Merge Request Security Widget
When scanning runs in an MR pipeline, GitLab shows a summary of new vulnerabilities directly inside the merge request page. Reviewers see security findings alongside the code diff without switching to a separate dashboard.
Merge Request #48 — Add payment integration
────────────────────────────────────────────────────
✅ Pipeline passed
⚠️ Security scanning detected 1 new vulnerability:
HIGH: Hardcoded secret detected in payment.js:34
────────────────────────────────────────────────────
[ View vulnerabilities ] [ Approve ] [ Merge ]
Dismissing a False Positive
Scanners occasionally flag safe code as a vulnerability. Open the finding in the Vulnerability Report, read the explanation, and click Dismiss vulnerability with a reason. Dismissed findings are hidden from the active list but preserved for audit purposes.
