What GitLab SAST gives you and when self-managed teams need it
GitLab SAST (static application security testing) reads your source code during a CI/CD pipeline and reports likely vulnerabilities without running the application. For a security or platform lead running self-managed GitLab, the practical question is whether static analysis should run on every merge request, which findings block a merge, and what infrastructure must exist before any of that works. The answer depends on the edition, the analyzers you enable and the runner capacity that executes them. The SAST model is analyzer-based. GitLab includes a template that adds an analysis job to a pipeline, and each job runs a language-specific analyzer as a container image on a runner. Analyzers are selected by the languages present in the project, and their output is converted into a common report format that GitLab reads. Scans are CPU and memory work, so a fleet with too few runners, or runners limited to small machines, shows up as queued or slow security jobs rather than as a visible security gap. Confirm the runner executor, image pull path and offline image handling before you commit to a design, especially on air-gapped networks.
Findings appear in merge requests as a widget showing new results compared with the target branch, which lets reviewers see what a change introduced. Triage and tracking happen in the vulnerability management views. Per the GitLab pricing page, application security testing and vulnerability management sit in the Ultimate tier, while Free and Premium differ on what is included, so check which SAST capabilities, including Advanced SAST, are available in each tier before you size licenses. Exact feature lists change between releases, so confirm them against the current pricing page and the SAST documentation for the version you run. When you plan the rollout, decide three things first: which tier your security requirements actually need, whether findings should block merges or only inform reviewers, and how many runners you will dedicate to security jobs so they do not delay build and test pipelines. Ask your DeployOpen or internal team to test these settings on a representative project before enabling them across the instance.
Which scanning capabilities sit on Free, Premium and Ultimate
GitLab Free costs 0 US dollars and is available for self-managed installations, so it is the cost baseline for the instance itself. Do not assume that scanning features come with it. Treat scanning on Free as an open question until GitLab confirms which SAST analyzers and merge request findings apply to the exact version you plan to install.
- Licensing cost: there is no subscription fee, so the spend is infrastructure, administration and any scanning tooling you run yourself.
- Scanner availability: confirm whether any SAST analyzers run at this tier and whether their results appear in merge requests.
- Self-managed fit: Free can host repositories and CI/CD, while scanning entitlements are decided separately.
- Self-run tools: teams often run open-source scanners as CI jobs on Free. Those jobs need their own runner capacity and a process for handling results.
- Version drift: scanner behavior can change between releases, so check entitlements against your target release, not an older one.
Record the Free entitlement answer in your design document before you assume any scanning gap is covered.
GitLab Premium is priced at 29 US dollars per user per month billed annually, and it is available for self-managed installations. The GitLab pricing page lists advanced CI/CD and priority support for Premium. It lists application security testing under Ultimate instead, so do not budget for Premium scanning features until GitLab confirms them in writing.
- Seat-driven cost: the recurring fee scales with the number of licensed users, so the seat count and the billing term are the first inputs to a quote.
- Advanced CI/CD: Premium adds pipeline capabilities that may change how scan jobs are structured, so review pipeline design with the scan plan.
- Scanner entitlements: confirm which SAST analyzers and merge request findings are included at Premium for your version.
- Support scope: priority support is listed for Premium, which matters when a scanner upgrade or runner issue blocks merges.
- Advanced SAST: ask GitLab directly whether Advanced SAST is available at this tier, since it is not listed in the pricing summary.
Before you approve a Premium budget for security scanning, get the entitlement list for your version and map each analyzer to the teams that will act on its findings.
GitLab Ultimate is custom priced and is available for self-managed installations. The pricing page lists application security testing, software supply chain security, vulnerability management and compliance features for this tier, which makes it the tier most associated with the full scanning and findings workflow. Pricing comes from a written quote, not a published rate.
- Application security testing: the pricing page places application security testing on this tier, so confirm which SAST analyzers and Advanced SAST capabilities are included.
- Vulnerability management: the tier lists vulnerability management, which determines how findings are triaged, tracked and reported across projects.
- Supply chain scope: software supply chain security is listed here, and it affects which SBOM and provenance outputs you can generate on your instance.
- Quote inputs: custom pricing depends on the user count, the features in scope and the deployment model, so give GitLab a precise scope.
- Compliance overlap: compliance features are also listed for this tier, so align scanning evidence with the controls you need to show.
Ask GitLab for a written entitlement matrix for your target version, and check it against the features your security team plans to use before signing.
Scanning runs as CI/CD jobs, so the capacity question applies to every tier that includes scans. GitLab Runner executes those jobs and is distributed under the MIT license. It supports shell, Docker and autoscaling executors across clouds and hypervisors. The scan workload has to fit the runner fleet you choose, and that fleet must be sized for merge request volume, not just for build jobs.
- Executor choice: Docker and autoscaling executors are common choices for scan jobs, but the right executor depends on your infrastructure and isolation needs.
- Version alignment: the docs advise keeping Runner major and minor versions aligned with GitLab, so plan runner upgrades alongside instance upgrades.
- Dedicated capacity: scan jobs can compete with build and test jobs for the same runners, so consider separate runners or queues for scans.
- Offline operation: GitLab documents separate guidance for running security scanners in offline environments, including analyzer image delivery.
- Egress rules: check whether your network allows analyzer images and vulnerability data to reach the runners, or whether they must be mirrored internally.
Size the runner fleet with the number of merge requests per day and the scan types you enable, then test that the queue stays acceptable under peak load.
Tier names do not tell you which analyzer or workflow you will get, and entitlements can change by release. Before you commit to a tier, build a written checklist and send it to GitLab with your target version and deployment model. Ask for answers in writing so that your procurement, security and platform teams work from the same source.
- Analyzer list: ask which SAST analyzers are included for each tier, and for which languages in your codebase.
- Advanced SAST: confirm whether Advanced SAST is included, and at which tiers, for your version.
- Merge request findings: confirm which findings appear in merge requests and whether they can block a merge under your policies.
- Vulnerability management: confirm which triage, tracking and reporting features are available at each tier.
- Offline needs: confirm the offline delivery method for analyzers and vulnerability data if your environment is air-gapped.
Bring the completed checklist to your quote request so that the scope, the tier and the runner plan are priced together.
How the SAST job runs inside your pipeline
SAST runs as an ordinary CI/CD job in the pipeline of each project that includes the scanner template. The job checks out the code, runs the analyzers that match the languages it finds, and writes its results to a report artifact in a machine-readable format. GitLab reads that artifact to populate merge request widgets and the security dashboard, so the scan is only as visible as the job that produces the report. Plan for the job to run in a pipeline stage that completes before any merge decision depends on it, and confirm in the current GitLab documentation which report type and artifact path the SAST template uses for your GitLab version, since those details change between releases.
Analyzer selection and configuration live in the project's .gitlab-ci.yml file, usually as an include of the SAST template followed by variable overrides for the job. Variables such as SAST_EXCLUDED_PATHS and analyzer-specific settings are set there, or at group and instance level where your administrators have standardized them. Decide early which settings are locked centrally and which teams may tune them, because a project that excludes large directories or disables an analyzer changes what the report can show. Check the analyzer list and language coverage in the current GitLab SAST documentation before you rely on any language being scanned, and test the job on a representative repository to see which analyzers actually run.
Findings appear on the merge request as a widget that compares the source branch with the target branch, so reviewers see new issues introduced by the change. Confirmed or triaged findings then flow into the project's vulnerability management views, where status, ownership and history are tracked over time. Ask your administrators to confirm which roles can dismiss findings and whether dismissal requires a comment, because that decision determines the audit trail. Also plan the runner capacity the scan needs: SAST jobs compete with build and test jobs for the same runners, so the runner configuration for your pipelines should be sized with the scan included.
Scanning configuration options and when each fits
This table compares the main ways to configure GitLab security scanning, from the default included template to Advanced SAST and offline analyzer delivery. Read each row for the situation it suits, the cost it carries in scan time or coverage, and the tier or infrastructure it depends on. Confirm analyzer names and variables against the current GitLab documentation for your release before you write pipeline configuration.
| Option | When it fits | Trade-off | Tier or infrastructure needs |
|---|---|---|---|
| Default analyzers through the included SAST template | First rollout, or teams that want language-specific SAST results with little pipeline design work | Coverage is what the default analyzers detect for your languages, and results may include findings you must triage | Confirm the analyzers included for your languages and whether the template is available on your tier |
| Customized analyzer variables | Teams that need to exclude test paths, tune rulesets or adjust analyzer behavior for a known codebase | Each tuning choice must be reviewed and maintained, and loose exclusions can hide real findings | Set in the CI/CD configuration; confirm variable names for your analyzer version |
| Advanced SAST on Ultimate | Organizations that need deeper cross-file analysis and have the budget and tier for it | Higher licensing cost and a longer analysis step than the default analyzers in most pipelines | Requires the Ultimate tier; the pricing page lists application security testing as an Ultimate feature |
| Scans on merge requests | Developers need feedback before code merges and reviewers want findings in the review | Adds scan time to every merge request pipeline, and branch-specific findings may need triage before merge | Needs runner capacity that can run scans on each merge request pipeline |
| Scans on the default branch only | Teams with long scan times or limited runner capacity that still need a complete record of the main branch | Vulnerabilities reach the main branch before they are caught, so review relies on later detection | Lower runner load; still requires vulnerability management setup to track results |
| Offline or air-gapped analyzer delivery | Instances with no internet access that must run scanners inside the network boundary | Analyzer images and rulesets must be mirrored and updated by your team on a planned cycle | Follow GitLab's offline guidance for scanners; confirm the images and update process with your administrators |
How much runner capacity scans need and what drives it
Scan runtime on a self-managed GitLab depends on what runs each time code changes, not on a fixed number of machines. The cards below cover the workload, executor and version decisions that determine how much Runner capacity your scans consume, and what to confirm in your own environment before you size the fleet.
Projects and merge requests per day
Scan load follows how often pipelines start. A project that opens many merge requests each day runs its SAST jobs on every push to those branches, so the daily count of merge requests across all projects is the first number to collect. Ask teams to count pipelines per day for the last month, then separate scheduled scans from merge request pipelines, because scheduled full scans often run longer than incremental ones.
Language and repository size
Analyzer runtime varies with the languages in each project and the size of the code it must parse. Large monorepos and projects with many build targets take longer per job than small services, even when they run the same analyzer. Run one representative scan per language and record the job duration, then multiply by expected daily runs rather than assuming a single average for the whole estate.
Concurrent pipelines
Queue time matters as much as job duration. When many merge requests open at the same time, scan jobs wait for free Runner slots, which delays merge request feedback for developers. Confirm the concurrency limit each Runner and the instance will allow, and identify peak windows such as release days, so the fleet is sized for the busiest hour rather than the average day.
Executor type and autoscaling
The executor decides how jobs are isolated and how capacity grows. Docker executors run each analyzer in a container and suit most scan jobs, shell executors share the host and need tighter hygiene, and autoscaling executors add machines on demand. Autoscaling on cloud VMs or hypervisors reduces idle cost but adds start-up latency, so test how long a fresh machine takes to become ready for a scan.
Runner version alignment
GitLab Runner is distributed under the MIT license and is a separate component from the GitLab server. The documentation advises keeping the Runner major and minor versions aligned with GitLab, so an upgrade of the instance usually requires a planned Runner upgrade in the same change window. Record the Runner versions in the fleet inventory and check them against each GitLab upgrade stop before scans start failing on mismatched components.
Setting up SAST on a self-managed instance
This sequence takes a self-managed GitLab instance from tier confirmation to working static analysis, with findings visible in merge requests and, on Ultimate, triaged in vulnerability management. Each step closes with a check so you know it is safe to move on.
Confirm tier and scanner entitlements
Before any pipeline work, confirm which edition and license your instance runs and which security scanning features that tier includes. The GitLab pricing page groups application security testing and vulnerability management under Ultimate, while Free and Premium cover a narrower set, so check the feature matrix for your exact version with your GitLab account team or the pricing page. Record the result, including whether Advanced SAST is in scope. The check: a written entitlement list that the security and platform leads have both signed off on.
Register a runner with a suitable executor
SAST jobs run as CI/CD jobs, so they need a GitLab Runner that your instance can reach. Your platform team registers a runner using an executor suited to your infrastructure, such as Docker on a dedicated VM or the Kubernetes executor if you already operate clusters. Keep the Runner version aligned with your GitLab version, as the Runner documentation advises. Use a runner that is isolated from production deployment credentials. The check: the runner appears as online in the instance admin area and picks up a trivial test job.
Include the SAST template in a pipeline
In a test project, add the SAST template to the project's
.gitlab-ci.ymlso the analyzers run as part of the normal pipeline. Confirm that the analyzers needed for your languages are pulled from a registry your runners can reach, which matters for offline installs later. Keep the template changes in a separate branch so reviewers can see exactly what was added. The check: a pipeline completes with a SAST job that reports success or a clear, documented failure reason.Run scans on a test project
Run the pipeline on a project with known, seeded weaknesses or with code your developers already understand, so you can judge whether the output is useful. Review the job logs for analyzer errors, unsupported languages and timeouts, and adjust runner resources if jobs are slow. Note which findings are false positives so the team can tune the approach before rollout. The check: the SAST report artifact is produced and the findings match what you expected from the seeded test code.
Review findings in merge requests
Open a merge request containing a deliberate change and confirm that SAST findings appear in the merge request widget with severity and location. Have a developer and a security reviewer each check that a finding is understandable enough to act on. Decide the team's rule for blocking merges, and document it before enforcing anything. The check: findings show on the merge request, link to the affected lines, and the team agrees on which severities block a merge.
Configure vulnerability management triage on Ultimate
On an Ultimate tier instance, open the project's vulnerability report and set up the triage workflow your security team uses. Assign owners, set states such as detected, confirmed, dismissed or resolved, and record a reason for each dismissal so auditors can follow the decision. Confirm who can change vulnerability states, since this is an access decision as well as a workflow one. The check: a test finding moves through the full state lifecycle and the dismissal reason is visible in the audit trail.
Confirm scanners work offline
If the instance runs air-gapped, repeat the pipeline run with network egress blocked, using the offline guidance GitLab publishes for its security scanners. Verify that analyzer images, rulesets and any advisory data are mirrored into your internal registry and reachable from the runner. Ask GitLab or your partner to confirm the exact mirroring steps for your version, since they change between releases. The check: a SAST job completes on the isolated network and produces the same report format as the connected run.
Security and operational considerations for scanning runners
Scanners run as CI/CD jobs, so the runner that executes them, the variables it can read and the network it can reach shape the risk as much as the scanner itself. The cards below cover the decisions to make before scans run on merge requests from people outside your trust boundary.
Isolate runners for untrusted merge requests
Merge requests from forks or external contributors can change the scanner configuration and the code being analyzed. Run those jobs on runners that are separate from production deployment runners, and use ephemeral executors such as autoscaled VMs or Kubernetes pods so no state survives between jobs. Check whether untrusted pipelines can reach protected variables and whether the runner shares a host or network with internal services. The runner must never be shared between untrusted and deployment workloads.
Limit secrets exposed in CI variables
Scan jobs inherit whatever CI/CD variables their pipeline can see, so a scanner or a malicious change to a job script can print or transmit them. Mark sensitive values as protected and masked, scope them to specific environments, and avoid placing deployment credentials in project-wide variables that scan jobs can read. Review which variables scan jobs receive before enabling scanning on existing projects, and rotate any value that has appeared in job logs.
Plan egress for analyzers and advisory data
Scanning on self-managed or offline instances needs access to analyzer container images and, for some scanners, vulnerability advisory data. Decide whether runners reach these from a internal registry mirror, a proxy or the open internet, and document each destination. In air-gapped environments, GitLab's offline guidance covers separate steps for security scanners. Confirm with GitLab exactly which images and data sources each scanner version needs before you open or close any firewall rule.
Control retention and access to findings
Scan reports, vulnerability records and merge request widgets can reveal unpatched weaknesses in your code to anyone with project access. Decide who can view and triage findings, which roles can dismiss them, and how long artifacts stay in the pipeline before expiry. Align artifact expiration and project visibility with your data classification, and confirm how dismissal reasons are recorded for audit purposes.
Keep the scanner stack on the release cadence
Scanner analyzers and the GitLab instance move together, and GitLab ships minor releases on a monthly schedule. Security fixes are backported to the previous two monthly releases, while bug fixes go only to the current stable release, so falling behind leaves known weaknesses unpatched. Schedule a monthly review of minor releases, keep Runner versions aligned with the instance, and check required upgrade stops before planning larger jumps.
Questions teams ask before scoping SAST work
How much does adding SAST cost on Free or Premium compared with Ultimate?
The cost depends first on which tier includes the scanning features you need, so confirm that on GitLab's pricing page before you budget. GitLab Free costs nothing, Premium is listed at 29 US dollars per user per month billed annually, and Ultimate is custom priced, which means its quote depends on seat count, add-ons and contract terms. The page places application security testing under Ultimate, so a Premium plan may not cover every scanner you want. The total also includes one-time implementation effort, recurring runner compute, and recurring time for developers and security staff to triage findings. Ask any partner for a quote that lists the tier, the scanners, the seat count, the runner plan and the training as separate lines.
How long does a SAST rollout take, and what drives the timeline?
The timeline depends mainly on how many projects and pipelines will be scanned, how many languages those projects use, and how much tuning the team expects before findings reach developers. Each project with its own CI/CD configuration adds review work, and shared pipeline templates can reduce it if they already exist. Runner capacity, approval workflows and any offline or air-gapped constraints also add steps. A rollout that starts with a pilot group of projects, then widens in stages, is easier to plan than an all-at-once switch. Ask for a phased plan in writing, with the pilot scope, the exit criteria for each phase and the decisions the client team must make before each phase begins.
What does the client team need to provide for a SAST engagement?
The client team needs to provide access and decisions. Expect to name a GitLab administrator who can change instance settings, a group owner for each set of projects in scope, and a pipeline owner who knows each project's CI/CD configuration. Someone must decide which tier the organization will buy and which scanners it needs. The security team should own the triage policy, including severity thresholds and who may suppress a finding. If runners will run on your infrastructure, the platform team must provide hosts or accounts, network paths and access to the image sources your jobs use. For offline instances, the team must also arrange how analyzer images and updates reach the network.
Can an internal team add SAST without outside help?
An internal team can add SAST alone if it already administers GitLab, writes CI/CD pipelines confidently and has someone who can run a pilot without disrupting releases. The harder parts usually lie elsewhere: confirming which features each tier includes, hardening the runners that execute scans, setting up scanning on an offline instance, and tuning results so developers trust them. Teams without recent experience in these areas often take longer to reach a usable state. A useful middle path is to run one pilot project internally, record every decision and configuration change, and then decide whether the remaining projects need outside help. Whichever route you choose, write down the ownership of the scanning pipeline before the pilot begins.
How many GitLab Runners does security scanning need?
No single number fits every instance, because scan jobs compete with build and test jobs for the same runner capacity. Capacity depends on how many pipelines run at the same time, how long each scan takes, and how many scans run on each merge request. Start by measuring queue time during the pilot, then add capacity where jobs wait. Autoscaling executors let the fleet grow and shrink with demand, and the Runner documentation describes the executor options. Keep Runner major and minor versions aligned with the GitLab version, since the documentation advises that. Also plan the runner hosts for isolation, because scan jobs run code from your repositories. Ask any partner to size the fleet from measured pipeline volume, not from an assumed count.
How should teams triage SAST findings without blocking every merge?
Start in a report-only mode, where findings appear on the merge request but do not stop the merge. Use that period to measure how many results are real, which rules produce noise, and which teams need training on the flagged patterns. Then set blocking rules only for high-severity findings in the projects where the team has tuned results. Assign each finding to a named owner, and require a reason for every suppression so that false positives can be reviewed later. Ultimate includes the vulnerability management features that track findings across projects, and the tier question affects how much of this workflow you can run in the platform. Agree on these rules with the security team before the first blocking rule goes live.
Does SAST work on an offline or air-gapped GitLab instance?
GitLab documents running self-managed instances in offline, air-gapped environments and publishes separate guidance for its security scanners, so offline scanning is a supported path to plan for, not an assumption to make. The practical questions are how analyzer images get into the environment, how rule and analyzer updates reach it, and who approves each transfer. Confirm each step against the offline guidance for your GitLab version before you commit to a design. Plan the update cadence, since an offline instance also has to follow GitLab's release and upgrade schedule. Ask for a written list of the artifacts that will cross the network boundary and the approval steps for each one.
How scope and quote follow the written plan
DeployOpen scopes SAST work in writing before any delivery starts. The written scope names the GitLab tier you will run, the projects and groups that will be scanned, the runners that will execute the scan jobs, and the environment the scanners must work in. Most engagements are fixed-scope, so the deliverables and the acceptance checks are agreed on paper before a quote is final. A quote follows from that document, not from a general estimate of what security scanning usually costs.
The quote depends on four inputs. The first is the tier decision: Free and Premium do not include Advanced SAST, merge request vulnerability management or the wider application security testing features that Ultimate adds, so the work on each tier differs. The second is the number of projects and the languages they use, since onboarding, analyzer tuning and triage of first results scale with that count. The third is the runner fleet, including whether capacity already exists or must be built, because scan jobs need runner capacity of their own. The fourth is offline need: air-gapped installs require the offline guidance for the scanners and a plan for updating analyzer content, which adds build and verification work. Ask each bidder to state which of these inputs they assumed.
Before you sign, confirm which items are one-time and which recur. Initial configuration, pipeline changes and the first triage are one-time costs. Tier licensing is billed per user per month on Premium (the pricing page lists 29 US dollars per user per month billed annually) and on Ultimate is custom priced, so ask your GitLab account team for the current Ultimate figure. Retained support, analyzer upgrades and rule tuning recur. Ask the bidder to show the change control path for scope changes, such as adding a project mid-engagement, so that a later request does not silently reopen the quote.
How DeployOpen delivers GitLab security scanning
DeployOpen plans, implements and hands over GitLab security scanning inside your own infrastructure, including runner capacity and the offline setup where it applies. Engagements are fixed-scope, so the scanners, tier decisions, runner design and evidence you receive are agreed in writing before work starts.
How we scope
- Confirm your GitLab tier and which scanners you need on Free, Premium or Ultimate before any build work begins
- Map languages, repositories and pipelines to the SAST analyzers and Advanced SAST coverage you plan to use
- Agree in writing whether merge request findings, vulnerability management and security policies are in or out of scope
- Identify whether the instance runs air-gapped, which changes how scanner content and updates reach your runners
How we build
- Configure SAST templates and analyzer settings in pipelines, with exclusions reviewed and recorded for each project
- Size and secure the runner fleet that executes scans, including isolation, tags and capacity for peak merge request volume
- Test findings on sample repositories so developers see merge request results that match the agreed scanner configuration
- Document each analyzer version and the update procedure so scanner changes follow your GitLab upgrade and change process
How we hand over
- Deliver a written runbook covering pipeline configuration, runner setup, triage workflow and vulnerability management ownership
- Provide test evidence showing scans ran, findings surfaced in merge requests and runners completed jobs as designed
- Walk your security and platform engineers through triage, false-positive handling and how to add new projects
- Record the agreed scope, tier assumptions and open items so your team can audit what was built and why
How we support
- Ongoing support, upgrades and continuous testing are available as retainers, scoped separately from the implementation
- Review scanner and runner versions against GitLab release cycles and required upgrade stops when your instance moves
- Re-run agreed scan tests after GitLab, runner or analyzer upgrades to confirm findings and pipelines still behave as documented
- Confirm with GitLab which capabilities your tier and offline setup support before planning changes to scanning scope

