Integrating Snyk Code into CI/CD: SAST with a low false positive rate

Static analysis is useful as long as reports don't drown in false positives: the team stops trusting them and misses real risks. We set up Snyk Code for your build pipeline turnkey — from run mode to exclusion policies. Noise in reports is reduced severalfold, and the blocking threshold becomes clear to both development and business.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Snyk Code in the pipeline: where false positives appear

Code scanning is most often built into the pipeline as the last step — after build and tests, sometimes only on the release branch.

By that point, Snyk Code analyzes the accumulated layer as a whole rather than the diff against the main branch: the report includes findings that have been sitting in the repository for months and have never caused a failure. The analysis formally works, but it does not show what the team wrote just now.

The second reason is the lack of a baseline. Until it is fixed which detections are considered already accepted, each build raises them again, and the share of false positives in static analysis grows with the codebase size.

An engineer opens a list of several hundred lines, spends an hour reviewing it, and finds one real issue — after the third such time, the report is not opened at all.

The cost of this bottleneck is concrete. Code scanning in the pipeline is switched to non-blocking mode so it does not interfere with releases, thresholds are weakened, and noise in the analyzer report piles up in the task queue unreviewed.

The class of defects that such review catches most cheaply — typical unsafe calls, external input handling, accidentally committed secrets — remains open while the scan formally works.

We explain how this is closed: we move the scan to the pre-merge stage, maintain a baseline for existing code, and configure thresholds so that only new findings block.

What changes after configuration: accuracy and speed of scans

After configuring the scan profile, not only the number of findings changes, but also who reviews them and when.

Snyk Code returns the result directly in the merge request — the engineer sees comments in the context of their own lines, not as a separate report at the end of the week.

A report without noise: exclusion rules

The accuracy of static analysis is configured at three levels: a set of checks for the language and project profile, exclusion rules for directories and files, and pinpoint annotations in code with a reason and review date.

Test data, generated schemas, and outdated modules are removed from the scan scope — the share of false positives drops so much that the report is read in full rather than skimmed.

An exclusion without a reason and review date is deferred debt: the rule is forgotten and not removed, and an entire class of defects stops being checked. Therefore, each exclusion is recorded in the configuration with a note of who added it and when they will revisit it.

Scan time on every change

The scan runs over changed areas rather than the entire codebase, with caching of results for unchanged modules. A response to a typical change arrives within minutes, before merge, so the defect is fixed in the same task rather than filed as a separate ticket. A full nightly run remains a safety net and updates the project baseline.

Findings are reviewed according to a common scheme: critical issues block merge, the rest are assigned to owners with a deadline. This is how scanning becomes part of the team’s working rhythm instead of living as a separate stage.

Scan integration options: comparison of modes

The Snyk Code analyzer connects to the pipeline at several points, and each point answers two questions in its own way: where code analysis runs and what exactly blocks changes from progressing. Below are the modes to choose between during implementation.

Option When it fits Limitations
Analysis in the developer’s editor Feedback is needed before changes are committed Requires setup on every machine, easy to bypass
Scan in the merge request Changes are small, the branch lives briefly Sees only branch changes, does not find inherited defects
Full analysis of the main branch A picture of accumulated debt is needed Takes longer, findings arrive after merge
Build scan before release It is important not to release a version with a defect Blocks release at the last moment

Scan on the developer side

Analysis runs in the editor and in a pre-commit hook: a hint arrives within seconds and applies only to changed lines. This is the best mode in terms of false positives — the author sees the context and removes an unnecessary rule immediately.

The limitation is discipline: a local hook is easy to bypass, so a second line of defense is needed.

Scan on the shared build side

Here the scan runs on the server: for every merge request and as a separate job on a full snapshot of the main branch. Blocking is enabled by severity threshold — the build fails only on a confirmed high-severity issue, and everything else goes to the report.

When connecting the analyzer to the pipeline, first enable report mode and only then the merge prohibition, otherwise the flow of changes will stall on reviewing accumulated debt.

Procedure for implementing Snyk Code in the build pipeline

Implementing a code analyzer begins not with configuration but with an audit of the build pipeline: it is important to understand which branches releases are built from and what already stops the build.

Without this map, static analysis will either lengthen every commit or turn into a report that no one opens.

  1. Build pipeline audit. A map of repositories, build stages, and existing checks: where analysis will fit before tests and will not delay feedback.
  2. Trial enablement on one service. Snyk Code runs in observation mode, without blocking: a couple of weeks of statistics on finding types and false-positive rate.
  3. Rule configuration. We move false positives into an exclusion file next to the code — rules change in the same branch as the edit and go through general review.
  4. Build blocking threshold. What stops the build and what only goes to the report — we cover this below.
  5. Rollout in waves. We connect the remaining repositories in groups by service criticality, and after each wave we check build time.
  6. Handover to support. A regulation: who updates exclusions, how a disputed finding is reviewed, whom to notify about a scan failure.

How we choose the blocking threshold

Only new high-severity findings in changed lines stop the build. We record accumulated code with a snapshot as of the start date: it is visible in the report but does not block work — otherwise the team would drown in edits to other people’s files.

We review the threshold once a quarter: as the snapshot is cleared, the share of blocking rules grows, and a red build remains a signal of a real problem in a specific edit.

Settings, exclusion policies, and documentation based on the results

Everything that remains after implementation lives in your repository and works without us. Below is the list of artifacts the team receives: they can be read, edited, and moved between platforms without looking into someone else’s head.

Configuration files and rule profiles

  • Snyk Code rule profile at the repository root: enabled scan categories, severity thresholds, build behavior for blocking findings.
  • Separate profiles for different code criticality — strict for the payment circuit, soft for internal utilities and scripts.
  • A list of exclusions with justification for each: path, rule, reason, review date. An exclusion without a reason is not accepted.
  • Access scheme: which engineers can change the profile and which only see the report. Rule changes go through code review, just like regular code.
  • Launch configuration in the build pipeline: in which branches analysis blocks the build and in which it only reports.

Instructions and review regulations

  • Instructions for running the analyzer locally — the engineer sees findings before submitting changes, not after the build.
  • Finding review regulations: response times by severity level, who closes them, how a confirmed false positive is marked.
  • Procedure for reviewing the exclusion list and profiles: once a quarter, with the decision recorded in the repository.

The documentation describes not the tool in general, but your rules of the game with it — this is what survives a change of contractor and the arrival of new engineers.

Case study: how static analysis noise was reduced by a factor of three

The project is several dozen services, and the build runs every few hours. Static analysis was connected, but no one opened the report: out of a hundred findings per release, only a few were confirmed; the rest were framework specifics, test data, and generated code.

Review took the on-duty engineer more than two hours, so the noise was simply cut off by threshold, and the build line blocking was eventually disabled.

We switched to Snyk Code and restructured not the analyzer itself but the way its output is handled: we labeled the detection history, moved rules for tests and migrations into separate profiles, and in the merge request scan left only the lines the author actually changed.

What had the greatest effect

  • the false-positive rate dropped from 61% to 19% — report noise stopped being a reason to ignore it;
  • the share of confirmed findings among blocking ones grew from 8% to 74%: the engineer spends time on what actually breaks the release;
  • report review dropped from two hours to 15–20 minutes, and scanning became part of the usual edit cycle.

What worked most strongly was separating findings into blocking and informational, together with limiting analysis to changed lines.

Rules stopped “making noise” on inherited code, and a new finding almost always relates to a fresh change — it is visible in context and it is clear who it is addressed to.

How does a build-time scan differ from a pre-merge scan?

The difference is in when the pipeline stops a change and what exactly it sees at that moment.

A build-time scan runs after changes are submitted: the pipeline builds the artifact and runs analysis over the whole project, so the answer comes several minutes later, when the author has already switched to the next task.

A pre-merge scan is tied to the merge request and starts before the code reaches the main branch. It works on the change: it takes the diff against the target branch and builds a data-flow graph for it — from the entry point to the changed line.

The comment reaches the author directly in the change discussion while the context is still fresh, and the merge is blocked until it is fixed.

This is exactly where feedback speed and completeness of change analysis diverge.

Incremental analysis fits into one or two minutes but looks only at affected paths: if a change in a shared library affects a call in another module, that connection will not make it into every scan.

A full run over the branch sees more, takes longer, and does not give the author an instant response.

Therefore, these are not alternatives but two levels of one scheme.

The merge request provides a fast barrier: Snyk Code analyzes the change and does not let it pass without a decision on each finding, while the build and the run over the main branch pick up cross-module connections and history where the incremental mode is blind.

As a result, the flow of comments to the author is measured in minutes, and analysis coverage does not sag.

Technical concerns: blocking threshold and exclusion rules

Below are the five questions engineers most often ask before enabling Snyk Code in the pipeline. The answers come from implementation practice: without promising “zero false positives,” only what is actually configured and verified on a live repository.

What exactly stops the build at the selected blocking threshold?

Only confirmed high-severity findings in changed lines; everything else goes to the report as a warning. The first sprints run in “do not block” mode — based on accumulated statistics, the threshold is calibrated to real noise, not to expectations.

How are false positives filtered out?

Incremental analysis of changed fragments and data-flow tracking produce noticeably less noise than signature-based checks. We review each questionable detection manually and record the conclusion so the same rule does not resurface in the next release.

How are exclusion rules structured, and do they turn into a hole?

An exclusion lives as a file in the repository: rule, scope, reason, owner, review date. An entry without an owner and date does not pass review — otherwise it quietly closes a real vulnerability for years.

Who is responsible for findings?

The service owner, not the security team: a finding goes into the same tracker as regular tasks, with its own priority. The security team retains the rules and threshold, while development is responsible for fixing within the deadline.

Can scans be enabled on existing code without stopping releases?

Yes: a baseline scan records the current state as the zero point, and after that only new code above the threshold is blocked. The old codebase is closed according to a plan, not with one emergency release.

Let’s discuss the task: what is needed from your team to start

To assess implementing Snyk Code in the pipeline, access to the production environment is not needed, and releases do not need to be frozen.

A description of the process and a few artifacts are enough — from them we estimate the scope of work, blocking thresholds, and rollout order.

  • A list of repositories and version control systems: monorepo or a set of services, languages and their shares.
  • Current pipeline configuration: stages, trigger conditions, and the point where we integrate the analysis step.
  • Criticality policy: which levels stop the merge and which only go to the report.
  • Baseline snapshot, if the analyzer has already been run: how many detections there are now and what share of them the team considers noise.
  • 5–10 examples of false positives with an explanation of why they are false.
  • Access: a service account with read-only access to code and permission to run jobs, and a list of environments.
  • Release regulations, a window for pipeline edits, and the pipeline owner on the team side.

Next, one working call focused on the matter, followed by an implementation estimate and a staged work plan: a pilot on one service, setting up noise suppression for your code, rollout to the remaining repositories, and handover of the pipeline to the team with regulations and documentation. No intermediate approvals are needed to start.