Integrating GitLab SAST and Dependency Scanning Into Existing PHP and Node Pipelines
AI generated
CI/CD
.yml
GitLab · CI/CD · Security
Integrating GitLab SAST and Dependency Scanning Into Existing Pipelines
Configuration, findings triage and false positive handling

Static code analysis and dependency checking are among the security features GitLab ships built in, and they can be wired into an existing .gitlab-ci.yml with just a few lines. The real work starts only afterwards: results need to be assessed, real vulnerabilities need to be prioritized, and false alarms need to be suppressed cleanly, without the security noise eroding developer trust in the tooling. This article covers integrating SAST and Dependency Scanning into an existing PHP or Node pipeline, and the practical handling of the findings that come out of it.

17 min read SAST Dependency Scanning Security Vulnerability Management

1. What SAST and Dependency Scanning Each Actually Do

Static Application Security Testing, or SAST, analyzes your own source code without executing it and looks for known insecure patterns such as unsanitized SQL queries, unsafe deserialization or hard coded credentials. Dependency Scanning, on the other hand, does not look at your own code but at the list of included third party packages, for instance from composer.lock or package-lock.json, and checks it against a database of known vulnerabilities. The two analyses complement each other, because a large share of real world security vulnerabilities today sit in dependencies rather than in hand written code.

GitLab ships ready made CI/CD templates for both analysis types, included via include:template, which automatically pick the right analyzers for the languages detected in the repository. For a PHP codebase this means semgrep as the SAST analyzer and gemnasium-php as the dependency scanner, for Node.js correspondingly semgrep and gemnasium-nodejs. This automatic detection removes a lot of manual configuration work, but only works reliably when the project structure follows the usual conventions of the respective language.

2. Wiring SAST Into an Existing Pipeline

The base integration is deliberately minimal: a single include:template entry for Security/SAST.gitlab-ci.yml is enough to automatically add the matching analyzer jobs to the pipeline. GitLab internally detects the languages present in the repository and only activates the analyzers that are actually relevant, so a pure PHP project does not end up running an unnecessary Java or Go scan alongside it. The results are stored as a SAST report artifact at the end, which GitLab automatically renders in the merge request widget as a list of security findings.

For existing, already grown pipelines it matters that the SAST job runs in the test stage by default. If that stage does not exist in your own .gitlab-ci.yml or is named differently, you either need to add test to your own stage list or explicitly assign the SAST job to an existing stage. A frequent stumbling block is also that SAST runs noticeably longer than the rest of the pipeline on very large monorepos, which is why a dedicated, parallel stage for security jobs often pays off, so the overall runtime is not extended unnecessarily.


# .gitlab-ci.yml
stages:
  - build
  - test
  - security
  - deploy

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

semgrep-sast:
  stage: security

3. Wiring In Dependency Scanning for PHP and Node

Dependency Scanning is included the same way via include:template with Security/Dependency-Scanning.gitlab-ci.yml, and automatically detects manifest files such as composer.lock, package-lock.json or yarn.lock. For PHP projects, composer install needs to have run before the scan job so the full dependency tree, including transitive packages, is available, otherwise the scanner only analyzes an incomplete subset. For Node projects the equivalent applies: npm ci or yarn install should run beforehand so the lockfile version matches what is actually installed.

An important practical difference from SAST is that Dependency Scanning depends on an externally maintained, regularly updated vulnerability database. New vulnerabilities in already included packages can therefore surface even if nothing in your own code has changed for weeks, simply because a new CVE was published for an existing dependency. This is exactly why combining it with a Scheduled Pipeline makes sense, checking for new findings regularly regardless of code changes.


# .gitlab-ci.yml
include:
  - template: 'Security/Dependency-Scanning.gitlab-ci.yml'

gemnasium-php-dependency_scanning:
  stage: security
  before_script:
    - composer install --no-dev --prefer-dist

4. How GitLab Presents and Prioritizes Findings

Every reported finding automatically gets a severity rating from Info through Low, Medium and High to Critical, based on the CVSS score of the underlying vulnerability or the rule classification of the SAST analyzer. In the merge request widget, new findings appear directly next to the affected line of code or package, so reviewers see them without opening a separate report. The security dashboard at the project and group level additionally aggregates all findings over time and makes trends visible, for example whether the count of open high severity findings is rising or falling.

For day to day prioritization it works well to focus exclusively on Critical and High findings first, and to handle Medium and Low findings in regular but less frequent reviews, for instance monthly instead of on every merge request. Without this prioritization a team quickly risks drowning in a flood of findings, many of which have limited real world impact, while the genuinely critical ones get lost in the noise.

5. From Finding to Resolved Issue: A Practical Workflow

A proven workflow starts by converting every Critical or High finding directly from the security dashboard into a GitLab issue, which GitLab allows in a single click and which automatically carries all relevant metadata like the affected file, line number and CVE reference. That issue then goes through the same prioritization and assignment process as any other bug, instead of disappearing into a separate, often neglected security list.

For Dependency Scanning findings, the fix is often a simple version bump of the affected dependency, achievable with composer update package-name or npm update package-name, followed by another pipeline run to confirm. For SAST findings in your own code, an actual code change is usually necessary, for example moving from unsafe string concatenation in a SQL query to a parameterized statement, which typically deserves its own merge request with review rather than a quick patch without a second pair of eyes.

6. Dealing With False Positives

No automated scanner is perfect, and both SAST and Dependency Scanning occasionally produce findings that, on closer inspection, are not real vulnerabilities. A classic example is a SAST finding for a supposedly unsafe function that in the specific context is already secured by upstream validation, or a dependency finding for a package whose vulnerable code path is not even used in the project. Simply marking such cases as resolved without documenting them leads the scanner to raise the exact same alarm again on the next run.

GitLab's security dashboard offers a way to explicitly mark a finding as a false positive, including a mandatory field for the justification. That marking is stored permanently and prevents the same finding from showing up as open again in future scans, as long as the underlying code or dependency version does not change. It is important to actually document these justifications carefully, since a later review by a security auditor otherwise has no way to understand why a finding was classified as non critical.


# .gitlab-ci.yml: excluding a path from SAST
variables:
  SAST_EXCLUDED_PATHS: "spec, test, tests, tmp, vendor/legacy-lib"

7. Controlling Pipeline Behavior With Thresholds

By default, a security finding does not automatically block the pipeline, it merely appears as information in the merge request widget, so developers are not blocked by every single low severity finding on every merge. For stricter requirements, a so called scan result policy can be defined via security policies at the group or project level, which for example automatically blocks any merge with an unresolved critical finding until either a fix or an approved exception is in place.

These policies can be configured granularly, for instance only applying to certain branches such as main, while feature branches remain free to develop against. In regulated environments where compliance requirements demand a documented approval for every known vulnerability, such a policy is often indispensable, while smaller teams frequently get by well with pure visibility in the merge request widget, without introducing hard blocks.

8. Impact on Pipeline Runtime and Resource Usage

SAST and Dependency Scanning jobs require their own, sometimes fairly memory hungry analyzer containers, which can noticeably extend a pipeline's overall runtime, especially on large codebases. In practice it has proven effective to place these jobs in a dedicated stage that runs in parallel with test jobs, rather than sequentially after the functional tests, so test and security runtime overlap instead of adding up.

For very large repositories it also helps to run Dependency Scanning not on every push, but only on merge requests against the main branch, plus additionally at night via a Scheduled Pipeline, as described in the earlier article on scheduled pipelines. This noticeably reduces CI minute consumption without compromising security, since new vulnerabilities in existing dependencies need to be detected regardless of when a commit happens anyway.

9. Best Practices for Sustainable Operation

Sustainable security scanning operations require clear responsibilities: who reviews new findings, who decides on false positive markings, and who escalates critical findings outside the normal sprint cadence. Without this clarity, findings become orphaned in the dashboard and the initial investment in the integration fizzles out, because nobody actually works through the reported problems.

Just as important is regularly watching the false positive rate: if it rises noticeably over time, that often points to an overly aggressive analyzer configuration, which can be reduced by targeted use of SAST_EXCLUDED_PATHS or by disabling individual rules that are irrelevant to the specific project. The table below compares the key properties of SAST and Dependency Scanning to clearly distinguish the two analysis types from each other.

Property SAST Dependency Scanning
Analyzes Your own source code Included third party packages
Data source Static analyzer rules External vulnerability database
Changes without code change No Yes, when a new CVE affects an existing package
Typical fix Code change with review Version bump of the dependency
Recommended cadence On every merge request Merge request plus nightly scheduled pipeline

Mironsoft

CI/CD pipelines, zero-downtime deployments and release automation

Deployments that run without downtime and without the nail-biting?

We review existing GitLab pipelines for fragile deployment steps and missing safeguards, then build a release process with zero-downtime deployments, automated checks and a rollback you can actually trust in an emergency.

Pipeline Review

Checking an existing .gitlab-ci.yml for fragility, missing stages and security gaps.

Zero-Downtime Deployment

Building symlink releases, health checks and rollback strategies for Magento stores.

CI/CD Automation

Connecting tests, security scans and deployments into one reliable pipeline.

10. Summary

GitLab SAST and Dependency Scanning: Key Takeaways

Two analysis types

SAST checks your own code, Dependency Scanning checks third party packages against a vulnerability database.

Minimal integration

A single include:template entry is enough, GitLab detects languages and matching analyzers automatically.

Triaging findings

Convert Critical and High into issues with priority, handle Medium and Low in regular reviews.

Document false positives

Explicit marking in the security dashboard with a justification instead of silently ignoring them.

11. FAQ: GitLab SAST and Dependency Scanning: Key Takeaways

1How do I wire SAST into an existing pipeline?
Through an include:template entry for Security/SAST.gitlab-ci.yml in .gitlab-ci.yml. GitLab automatically detects the languages present in the repository and activates the matching analyzers, with no further configuration needed.
2Does composer install need to run before the Dependency Scanning job?
Yes, for PHP projects composer install needs to run beforehand so the full dependency tree, including transitive packages, is available to the scanner. Otherwise only an incomplete subset of dependencies gets checked.
3Where do I see new security findings?
Directly in the merge request widget next to the affected line of code or package, as well as aggregated in the security dashboard at the project or group level, which also shows trends over time.
4How do I mark a finding as a false positive?
In the security dashboard, every finding can be explicitly marked as a false positive, including a mandatory justification field. The marking stays in place as long as the affected code or package version does not change.
5Does a found critical finding automatically block the merge?
Not by default. A scan result policy needs to be explicitly set up at the group or project level, which specifically blocks merges with unresolved critical findings until a fix or approved exception is in place.
6Why do new findings appear even though the code has not changed?
Dependency Scanning relies on an externally maintained, regularly updated vulnerability database. When a new CVE is published for an already included package, the finding shows up on the next scan, even without any code change of your own.
7How do I exclude certain directories from SAST?
Through the SAST_EXCLUDED_PATHS variable, which accepts a comma separated list of paths, for example test directories or legacy code that should deliberately not be scanned.
8Does SAST noticeably slow down the pipeline?
On larger codebases, yes. It is recommended to place SAST and Dependency Scanning jobs in a dedicated stage that runs in parallel with functional tests, so overall runtime is not extended sequentially.
9Should Dependency Scanning run on every push?
For very large repositories it makes sense to run it only on merge requests against main, plus additionally at night via a scheduled pipeline, saving CI minutes without missing new vulnerabilities.
10How do I handle the volume of Low and Medium findings without overwhelming the team?
It works well to focus on Critical and High findings in day to day work, and to handle Medium and Low findings in a separate, less frequent review cadence, for instance collected monthly.