OWASP Dependency-Check in the Build: Where the Bottleneck Is
OWASP Dependency-Check is added to the build as a mandatory step: until the library check passes, the artifact is not published.
In a project with hundreds of direct and transitive dependencies, this step quickly becomes the build bottleneck — it alone takes more time than compilation, tests, and packaging combined.
The first reason is working with the vulnerability database. On a clean agent, every run downloads and rebuilds the local index again: tens of thousands of records, long network operations, fluctuating timeouts.
The build fails not because of code, but because an external source is unavailable, and a restart does not guarantee that the next run will pass.
The second is the stream of false positives. Matching by coordinates and heuristics regularly marks a safe library as vulnerable: the package identifier could not be determined, the version was not recognized, the name matched.
Such noise blocks release, and the team takes one of two paths: disables the step entirely or weakens the threshold to a point where real vulnerable dependencies pass unnoticed.
The third is non-reproducibility. The result depends on when the database was updated and which modules managed to load. The same commit is green today and red tomorrow, and there is nothing with which to compare two reports between runs: the sets of findings are incomparable.
Next, we look at how this is addressed: caching the database between builds, limiting the analysis scope, a suppression file with justification for each entry, and committing the report as a build artifact.
What Changes After Implementing SCA Control
Before implementation, dependency analysis ran in full on every change, and build time grew linearly with the number of modules. The more services in the repository, the longer the wait for a verdict — and the more often the check was bypassed.
OWASP Dependency-Check together with analysis result caching changes this arithmetic: only changed branches of the dependency tree are recalculated, while the rest is restored from cache.
Build time stops growing with the number of modules and is determined by the actual volume of changes.
The cache key is tied to the dependency lock file and the vulnerability database version, so repeated analysis on the same revision produces an identical report.
This is the reproducibility of the check: the result in the build environment and on the engineer's machine matches, and a disputed finding can be investigated locally without waiting in line.
Next, the finding suppression policy works. Each exception is a separate entry with justification and a review deadline: the vulnerable function is not called, the transitive dependency comes only into the test scope.
The share of false positives drops severalfold — the report keeps dozens of real findings instead of hundreds of noise items.
The build stops when the specified severity threshold is exceeded, so the failure class of "a vulnerable library shipped to release" is closed at entry. The check stops being a brake and works as a filter: only reviewed dependencies pass further.
Dependency Check Run Modes: Comparison
Analysis run modes differ not in strictness but in what each caches between runs and at which step it stops the build.
A full run gives a complete picture, but on a large repository it adds tens of minutes to every build; incremental checking by changed modules fits within minutes, but sees only affected dependency branches.
| Mode | When it fits | Limitations |
|---|---|---|
| Full analysis on every commit | Few modules; reaction to any new dependency matters | Build time grows with repository size; teams start bypassing the check via forced skip |
| Incremental by changed modules | Monorepo with frequent commits | Requires a correct module graph: a transitive dependency may change in an unchanged module and remain unnoticed |
| Scheduled check | Large repositories with infrequent releases | Between runs, a vulnerable version can make it into the main branch, and the result goes to someone other than the person who made the change |
| Only before release build | External deliveries and environments with formal acceptance | Late feedback: dependency fixes surface at freeze, and vulnerability debt accumulates between releases |
How the Modes Combine
Incremental analysis on commits filters out the obvious, shared cache storage across runs and agents eliminates re-downloading the vulnerability database and keeps response time stable, and a full run before release acts as a gate.
The limitations of analysis — false positives and dependencies without public vulnerability identifiers — are addressed by a suppression file, but each suppression must have a review deadline, otherwise exceptions live for years and hide real findings.
Implementation Sequence: From Audit to Handover
Implementation is split into seven steps, and each ends with a verifiable artifact — a configuration, schema, or procedure, not a progress report.
The order is arranged so that the first stages do not touch working branches: first we capture the picture, then we change the pipeline. This way dependency analysis does not block release at the worst possible moment, and the team has time to get used to the new checks.
- Build pipeline audit: record where artifacts are built, which steps are cached, how long a clean build takes, and where external libraries appear in it.
- Dependency inventory: collect a list of direct and transitive components, mark outdated and abandoned ones, and note modules with the widest dependency tree.
- Cache schema: OWASP Dependency-Check pulls the vulnerability database on every run — move it to a separate volume tied to the database version so repeated builds do not download it again and do not lose results when the network fails.
- Run setup: choose the scanning mode, set of report formats, timing relative to tests, and the threshold at which the build stops.
- Suppression rules: describe findings that do not relate to our code, with a mandatory comment and review deadline — otherwise the noise quickly devalues the report.
- Testing on real builds: run the configuration on several modules, measure the build time increase and the share of findings that actually require fixes.
- Handover of procedures: deliver a document on database update order, handling new findings, and reviewing suppressions; hold a walkthrough with the team and stay in touch during the first changes.
Deliverables: Configurations, Policies, Procedures
The deliverables are assembled so that dependency analysis lives in your repository without our involvement.
After OWASP Dependency-Check implementation, configurations, policies, and instructions remain — enough for a new engineer to set up the check and understand why the report looks the way it does.
- Analysis configuration — a single profile: list of scanned modules, depth of transitive dependency analysis, report formats, and the condition for the build step to exit with a non-zero code.
- Cache schema — which set of files the key is tied to, when it is reset, and how the vulnerability database is stored so repeated runs do not pull it again.
- Suppression lists — an XML file where each entry has justification, owner, and review deadline; an entry without a comment does not pass review.
- Finding thresholds — separate rules for the release branch and for everyday work: what stops the build and what goes as a warning into the report.
- Developer instructions — how to run the check locally before committing, how to read the report on transitive dependencies, and when suppression is created.
- Vulnerability database update procedure — schedule and control of actual updates: without this, the report is built on outdated data and looks deceptively fine.
All of this lives in the repository and goes through review like code: threshold changes are visible in history, and suppression entries can be referenced during incident investigation.
Case Study: How Build Time and Number of Findings Changed
On one pipeline, the dependency check ran in full on every commit: the tool downloaded a fresh vulnerability database, ran all modules, and returned a report of several hundred lines.
The build took 16 minutes, and the step was mandatory — an edit to a small service waited for the full run.
What Was Changed
The OWASP Dependency-Check database began to be cached between runs and updated on schedule rather than on every commit; the key became the checksum of the dependency file — if it changes, the database is re-read; if unchanged, it is taken from storage.
A suppression list was introduced: each exception has a vulnerability ID, module, justification, and review date, so it is a decision with an owner, not a line to make the build pass.
What the Result Was
A typical build dropped from 16 to 4 minutes, and the full run with database update remained in the nightly schedule.
The share of noise findings fell from 78% to 15% — mainly due to exceptions for test-environment dependencies and vulnerabilities without an applicable attack vector.
Real findings became visible: over a quarter, three critical vulnerabilities in libraries reached the team, one in a component that was pulled transitively and was not covered by manual review. Trust in the check rests on the report being short and every finding already reviewed by someone.
How Does Dependency-Check Differ from License Checking?
Dependency-Check answers one question: what known vulnerabilities exist in the project's third-party libraries.
It reads manifests and lock files, compares versions against vulnerability databases, and returns a report with severity and the path to the problematic transitive dependency — but it does not analyze the project's own code.
License checking solves another task: whether the product can be shipped with this library. The license type, copyleft conditions, and attribution requirements matter — the result here is legal risk, not vulnerability. A scanner will show the license in the report, but the verdict remains with the lawyer.
| Check | What it finds | What it does not see |
|---|---|---|
| Dependency-Check | known vulnerabilities in libraries, including transitive ones | own code, secrets |
| License checking | license type, copyleft, attribution requirements | exploitability, legal verdict |
| Secret scanning | keys and tokens in files and commit history | vulnerabilities in dependencies |
| Static code analysis | insecure data flows in our code | versions of connected libraries |
Secret scanning and static analysis work on our codebase: one looks for keys and tokens in files and commit history, the other for insecure data flows. Neither will see a vulnerability inside a transitive dependency.
The boundaries of responsibility run along the data source: dependency scanning reads manifests, while static analysis and secret scanning read our code.
Intersections occur in the pipeline, so we keep false-positive suppressions centralized — otherwise one library surfaces in three reports under different wording.
Technical Concerns: Cache, Noise, Database Updates
Engineering concerns around the SCA loop are usually the same: how fresh the database in cache is, what to do in an isolated environment, and whether finding suppression will turn into a dumping ground. Below are short answers for each point, with what goes into the report and build configuration.
Does the vulnerability database in the cache become outdated between runs?
The cache is tied to the checksum of the database file: download happens only when it changes, and the update schedule is once a day. The report records the database version and the time it was generated, so for each run it is visible what data produced the result.
If the update did not go through, the build does not "go green" silently — it is marked as a check on an outdated database.
The build runs without external network access — is updating possible?
Yes. We set up an internal mirror: one node pulls the file over an allowed route, and the other builders take it from internal storage. Dependency analysis itself works offline from the local cache and does not need external requests.
The mirror address and proxy parameters are described in the configuration so moving to a new environment does not break the check.
The library cannot be updated — will the noise remain forever?
Finding suppression (suppression) works for such cases: a rule is tied to the vulnerability ID and a specific artifact rather than disabling the check entirely. Each entry has a reason, owner, and review date — an outdated suppression appears as a separate block in the report.
We reduce rule maintenance to a quarterly review: the report shows the share of false positives and the number of active suppressions, and we use them to decide what to clean up.
Let's Discuss the Task: What to Send for Assessment
For the assessment to be based on facts rather than generalities, we need a snapshot of the current build pipeline: what is used to build the modules, at which stages checks are already run, how long one run lasts, and where it hits the limit.
The nature of the project is also important — a monorepo with hundreds of transitive dependencies and a small service with a dozen direct libraries require different OWASP Dependency-Check run modes and different depths of vulnerability database caching.
- Pipeline diagram: stages, order of steps, where dependency analysis currently runs, and what happens when the build fails.
- Dependency files for each module: manifests and lock files, direct and transitive libraries, the share of internal packages from a private repository.
- Examples of noisy findings: vulnerabilities without an available fix, false matches by package name, entries already accepted as ignored — we use them to build a suppression file with justification.
- Time budget: how many seconds or minutes may be added to the build, whether runs only on changed modules are needed, and whether a report in "non-blocking" mode is acceptable.
- Network restrictions: whether there is access to external vulnerability database sources, whether an internal mirror repository and offline data updates are needed.
- Where to put results: report format, storage location, whether export to a quality control system and notifications to the team channel are needed.
- Criticality policy: which levels stop the build, who approves exceptions, and how often we review the suppression list.
With this set, we come back with an assessment and implementation plan: a list of stages, rollout order to one service, then the rest, and rollback points where you can roll back without stopping development.







