GitLab CI can automatically scan your code for security vulnerabilities as part of your pipeline, catching issues before they reach production.
Let’s see it in action. Imagine a simple Node.js app with a dependency that has a known critical vulnerability.
// server.js
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`App listening on port ${port}`);
});
And a package.json that includes a vulnerable version of lodash:
{
"name": "vulnerable-app",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.17.1",
"lodash": "4.17.10" // Known vulnerability here
}
}
To integrate Dynamic Application Security Testing (DAST), you’ll typically add a stage to your .gitlab-ci.yml file. GitLab provides built-in DAST templates that make this straightforward.
stages:
- build
- test
- dast # Dynamic Application Security Testing stage
include:
- template: Security/DAST.gitlab-ci.yml
variables:
DAST_WEBSITE: "http://your-application-url.com" # Replace with your app's URL
DAST_EXCLUDE_URLS: "/logout,/exit" # Optional: URLs to exclude from scanning
When this pipeline runs, GitLab will:
- Build your application: This stage would typically involve
npm installand potentially building your front-end assets. - Test your application: This could include unit tests, integration tests, and importantly, ensuring your application is running and accessible.
- Run DAST: GitLab’s DAST job will spin up a scanner (often based on tools like OWASP ZAP) and point it at your running application (
DAST_WEBSITE). The scanner will then crawl your site, sending various malicious-looking requests to identify common web vulnerabilities like Cross-Site Scripting (XSS), SQL Injection, insecure configurations, and more.
The DAST scanner interacts with your running application. It’s not analyzing your source code directly (that’s SAST – Static Application Security Testing). Instead, it’s probing the live application from the "outside," mimicking what an attacker would do. This means it can find vulnerabilities that arise from the interaction of your code, your dependencies, and your server configuration, which SAST might miss.
The key levers you control in DAST are primarily around what gets scanned and how.
DAST_WEBSITE: This is the most critical variable. It tells the scanner where to find your application. For local development or testing environments, you might need to ensure your application is publicly accessible or use GitLab’s Review Apps feature.DAST_AUTH_URL,DAST_USERNAME,DAST_PASSWORD,DAST_TOKEN: If your application requires authentication, these variables allow the DAST scanner to log in and scan protected areas.DAST_BROWSER_LIKE: This setting can influence how the scanner behaves, sometimes making it more closely mimic a real browser.DAST_EXCLUDE_URLS: Essential for preventing the scanner from getting stuck in loops or scanning sensitive logout/exit endpoints.
The DAST job will produce a dast-report.json artifact. GitLab then parses this report and displays the findings directly in your Merge Request, giving you actionable insights.
A common pitfall is forgetting to make your application accessible to the DAST scanner. If your DAST_WEBSITE points to an internal IP address or a service that isn’t running when the DAST job executes, the scan will fail or report no findings because it can’t reach the target. Ensure your CI/CD pipeline deploys your application to a reachable environment (like a staging server or a Review App) before the DAST stage.
The next step is often integrating SAST for a more comprehensive security posture.