skip to content

How do you handle false positives from dependency-check, and what goes into a suppression file?

level: seniorimportance: should knowfreq 35%

answer

  1. CPE guessing -> false positives
  2. <suppress> by sha1/GAV/cpe + <cve>
  3. suppressionFiles config
  4. report 'suppress' button generates XML
  5. justify + date + narrow scope

basics

~20 s

You write a suppression.xml file listing specific CVEs to ignore for specific dependencies, then point the plugin at it. It tells the scanner that a particular finding is a false positive (or accepted risk) so it stops failing the build.

solid answer

~40 s

Dependency-check infers each library's identity by guessing a CPE from JAR metadata, and that guessing produces false positives — a CVE for an unrelated product gets matched to your JAR. You suppress these in an XML suppression file referenced via `<suppressionFiles>`. Each `<suppress>` entry scopes itself to a dependency (by sha1, GAV regex, file path, or CPE) and lists the `<cve>` or `<vulnerabilityName>` to ignore. The discipline matters: every suppression should be justified (false positive vs. accepted risk), ideally dated, and reviewed, because a stale or overly broad suppression silently hides real vulnerabilities. The HTML report has a 'suppress' button that generates the exact XML snippet for a finding, which you copy into your committed suppression file rather than ignoring globally.

code

xml · 5 lines
xml
<suppress>
  <notes>Accepted risk: no fix yet, mitigated by network controls. 2026-06-21.</notes>
  <packageUrl regex="true">^pkg:maven/org\.example/legacy-lib@1\.2\..*$</packageUrl>
  <cve>CVE-2024-99999</cve>
</suppress>

go deeper

for a junior

Know there is a suppression.xml that tells the scanner to ignore specific findings.

for a middle

Know how to scope a <suppress> entry to a dependency and a CVE and wire it via suppressionFiles.

for a senior

Enforce narrow scoping, justification notes, and the false-positive vs. accepted-risk distinction.

for a principal

Set suppression governance: review cadence, ownership, and tooling so suppressions cannot rot into hidden risk across the org.

## Why false positives happen The plugin does not have a perfect map from JAR to product. It collects **evidence** (groupId, artifactId, manifest entries, embedded pom, package names) and guesses a **CPE** (the standardized product name). Guessing means it sometimes matches a CVE for a *different* product that shares a name — e.g. matching a Spring CVE to an unrelated library called 'spring-something'. These are **false positives**. ## The suppression file A suppression file is XML that tells the scanner: 'for this specific dependency, ignore this specific finding.' You reference it in config: ```xml <configuration> <suppressionFiles> <suppressionFile>dependency-check-suppressions.xml</suppressionFile> </suppressionFiles> </configuration> ``` The file itself: ```xml <?xml version="1.0" encoding="UTF-8"?> <suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd"> <suppress> <notes>False positive: CPE mis-match, this is acme-utils not Acme CMS. Reviewed 2026-06-21 by KD.</notes> <packageUrl regex="true">^pkg:maven/com\.acme/acme-utils@.*$</packageUrl> <cve>CVE-2023-12345</cve> </suppress> </suppressions> ``` ## How to scope a suppression You can target by: - **sha1** of the exact JAR (narrowest, most precise), - **packageUrl / GAV** (with `regex="true"` for version ranges), - **filePath**, - **cpe** or **gav**, and then suppress specific `<cve>`, `<vulnerabilityName>`, or `<cpe>` entries. Prefer the narrowest scope so you do not accidentally silence real CVEs on the same artifact. ## Generating entries The HTML report shows a **suppress** link next to each finding that emits a ready-made `<suppress>` block. Copy it into your committed file and add a justification note. Never blanket-suppress whole artifacts unless you truly accept all their risk. ## Governance - **Justify every entry** in `<notes>` (false positive vs. accepted risk + who/when). - **Review periodically** — a suppression added for one CVE may hide a new real CVE if scoped too broadly. - **Commit it** to the repo so the gate is reproducible. False positive (mis-matched CVE) and accepted risk (real CVE you cannot fix yet) are different decisions; document which one each suppression is.

  • What is the danger of suppressing by artifact name without scoping to a CVE?
    It silences every current and future vulnerability for that artifact, so a new genuine CVE would slip through undetected.
  • Why distinguish a false positive from an accepted risk in the notes?
    A false positive is permanent (wrong match); an accepted risk is temporary and should be revisited and removed once a fix exists, so the notes drive future review.

saying these in an interview costs you the question

  • Suppressing globally by GAV with no CVE scope, hiding future real findings.
  • Adding suppressions with no justification, making review impossible.
  • Treating every finding as a false positive instead of triaging real CVEs.

context