Vulnerable dependency handling approach by case
The Vulnerable Dependency Management Cheat Sheet defines five cases for handling detected vulnerable dependencies: Case 1 applies when a patched version has been released and tests exist to validate the fix. Case 2 applies when the provider indicates a fix will take months and can provide workarounds or information about impacted functions. Case 3 applies when the provider will not or cannot fix the issue at all. Case 4 applies when the vulnerability is discovered via full disclosure or penetration testing before the provider is aware. Case 5 applies when a patched version exists but cannot be adopted due to breaking changes, transitive dependency pins, or unsupported version lines, requiring backporting of the fix.
Case 1: Patched version released - update and test approach
When a patched version has been released: Step 1 is to update the dependency version on a testing environment. Step 2 is to run existing automated unit, integration, functional, or security tests. If all tests pass, push the update to production. If tests fail, determine whether the failure is due to changed function signatures (requiring code updates and re-testing), incompatibility with the fixed version that cannot be adopted (apply Case 5 with Case 2 interim mitigation), or technical incompatibility with the runtime (raise the issue to the provider and apply Case 2 while waiting).
Case 2: Delayed fix - protective code wrapper approach
When a fix will take months: Step 1 is to apply any workaround the provider gives and validate it in testing before production deployment. If the provider lists impacted functions, wrap calls to those functions with protective code validating input and output safety. Web Application Firewalls can also add parameter validation and detection rules. Step 2 is to execute exploitation code against the protective wrapper if provided, then run automated tests to verify the protection does not impact stability. Add a comment in the README explaining the CVE is being handled during the wait. The dependency can be added to an ignore list but only for the specific CVE, as a dependency may have multiple CVEs.
Case 2 example: RCE vulnerability protective wrapper in Java
Example Java code showing how to wrap a function with a Remote Code Execution issue: use Pattern.matches() to validate external input against a whitelist regex pattern like '[a-zA-Z0-9]{1,50}' before calling the flawed function. If validation fails, log the exploitation attempt using SecurityLogger.warn() with the CVE identifier and raise an exception that returns a generic error to the client. This ensures only safe input reaches the vulnerable function.
Case 3: Provider will not or cannot fix - patch yourself approach
When the provider refuses to fix or does not answer: This case is complex and time-consuming, used as a last resort. Step 1 is to consider whether to find a better-maintained alternative component or pressure the provider via Chief Risk Officer or Chief Information Security Officer. Step 2 is to identify where the vulnerable dependency is used in the application (including transitive dependencies via IDE or dependency management system like Maven, Gradle, NuGet, npm). Read the CVE description to determine the vulnerability type (SQL injection, RCE, XSS, etc.) to know what kind of patching is needed. Step 3 is to create a unit test mimicking the vulnerability and ensure it fails against the unpatched version and passes against the patched version. Run the dependency's own test suite and application tests to verify stability. Suppress detection tool alerts per CVE only after confirming the patch is effective. The tool will continue flagging the dependency based on version number, requiring scoped suppression rather than version string changes.
Case 3 example: Jackson XXE vulnerability patching
Example of handling CVE-2016-3720: Jackson's XmlMapper has an XML external entity (XXE) vulnerability. Based on the CVE description, the patching approach is to add pre-validation of any XML data passed to the Jackson API to prevent XXE attacks, following the XML External Entity Prevention Cheat Sheet.
Case 4: Vulnerability discovered via full disclosure or penetration test
When the vulnerable dependency is discovered through full disclosure posts on the Internet or during a penetration test: Step 1 is to inform the provider about the vulnerability by sharing the post or feedback. Step 2 is to use information from the full disclosure post or pentester's exploitation feedback. If the provider collaborates, apply Case 2. If the provider does not cooperate, apply Case 3, but analyze information from the full disclosure post or pentester feedback instead of the CVE.
Case 5: Fixed version exists but cannot be adopted - backporting
Backporting applies when a patched version is released but cannot be adopted because: the fix only ships in a new major version that breaks the application code, the vulnerable version is pinned by a transitive dependency that has not been updated, or the version line in use is no longer maintained and the fix landed only on a newer line. Backporting means taking the security fix from the upstream package and applying it to an older version that the project can run. Step 1 is to confirm the upgrade is really blocked by attempting it on a testing environment (as in Case 1) before deciding to backport. Step 2 is to isolate only the security-relevant change from the upstream release, keeping the patch minimal without refactoring, renaming, or unrelated bugfixes. Step 3 is to verify the patch with tests that reproduce the vulnerability, must fail against unpatched and pass against patched dependency, plus verify the dependency's own test suite and application tests still pass. Step 4 is to distribute the patched artifact through an internal registry or proxy rather than committing locally built files. Give it a version identifier traceable to the upstream version and record provenance (source commit, CVE, producer). Step 5 is to treat the patch as ongoing work, re-testing at each new upstream release and dropping the backport once the fixed version becomes adoptable.
Transitive dependency vulnerability handling
If a vulnerability impacts a transitive dependency, action must be taken on the direct dependency of the project, not the transitive dependency itself. Acting on transitive dependencies often impacts application stability. Identifying how the project's direct dependency uses the transitive dependency and understanding the complete communication chain is very time-consuming. Developers should use their IDE's built-in features or dependency management system to trace transitive dependencies.
Vulnerability detection disclosure methods: responsible disclosure
In responsible disclosure, a researcher discovers a vulnerability and collaborates with the component provider to issue a CVE (Common Vulnerabilities and Exposures) identifier. If the provider refuses to fix the issue despite accepting the CVE, or if the researcher does not receive a response in 30 days, full disclosure may follow. The vulnerability is referenced in the CVE global database used by detection tools as a primary input source.
Vulnerability detection disclosure methods: full disclosure
In full disclosure, a researcher releases all vulnerability information including exploitation code on services like the Full Disclosure mailing list or Exploit-DB. A CVE is not always created for full disclosure vulnerabilities, so the vulnerability may not appear in the CVE global database. Detection tools may be blind to these vulnerabilities unless they use additional input sources beyond the CVE database.
Risk acceptance authority for vulnerable dependencies
When a security issue is detected in a dependency, the decision to accept the risk must be taken by the Chief Risk Officer (with fallback to Chief Information Security Officer) of the company, based on technical feedback from the development team that analyzed the issue and CVSS score indicators.
Automated dependency analysis timing recommendation
It is highly recommended to perform automated analysis of dependencies from the beginning of the project. If dependency analysis is added in the middle or end of the project, it can result in a huge amount of work to handle all identified issues, creating a substantial burden on the development team and potentially blocking project advancement.
Vulnerable dependency detection tool selection criteria
When selecting a vulnerable dependency detection tool, ensure it: uses several reliable input sources to handle both vulnerability disclosure ways (responsible disclosure and full disclosure), and supports flagging issues raised on a component as false-positives.
Free vulnerable dependency detection tools
Free tools for detecting vulnerable dependencies include: OWASP Dependency Check (full support for Java and .Net, experimental support for Python, Ruby, PHP Composer, NodeJS, C, C++), NPM Audit (full support for NodeJS and JavaScript with HTML report option via npm-audit-html module), OWASP Dependency Track (for managing vulnerable dependencies across an organization), Trivy (full support for Base OS, Java, NodeJS, JavaScript, Ruby, Python, Go, .NET, Rust, PHP, Dart, Swift; targets Kubernetes, Docker, filesystem, Git repositories, cloud images), and Grype (full support across mainstream languages with SBOM-driven scanning for container images, filesystems, and SBOMs from Syft).
Commercial vulnerable dependency detection tools
Commercial tools for detecting vulnerable dependencies include: Snyk (open source and free option available, full support for many languages and package managers), JFrog XRay (full support for many languages and package managers), and Renovate (allows detecting old dependencies, full support for many languages and package managers).
Backporting from Linux distributions as reference model
Linux distribution security teams provide a reference model for maintaining vulnerable dependency patches. Debian and Red Hat both backport security fixes into stable release versions instead of upgrading. When a dependency is consumed as an operating system package, take the distribution's patched build rather than maintaining a private patch.
Criteria for evaluating maintained backport providers
When choosing between maintaining patches in-house versus paying someone to maintain them, evaluate maintained backport providers on: coverage of the ecosystems, version lines and severities the project depends on with published response time, publication of the patch and its provenance for review instead of blind trust, delivery as a compatible artifact through a registry or proxy the build already uses without manifest rewrites, and a documented way to leave the source without requiring re-patching from scratch.
Version string changes do not remediate vulnerabilities
Silencing a detection tool alert by changing a version string or bumping a version number does not constitute remediation. Detection tools flagging a dependency based on version number will continue to flag backported or patched versions because looking at the version number does not indicate whether the fix is present. The proper approach is to suppress the alert using a scoped suppression per CVE, not to change the version string.
CVE-specific suppression for multiple vulnerabilities per dependency
Dependencies can be impacted by multiple vulnerabilities, each with its own CVE identifier. When adding a dependency to an ignore list or suppressing detection tool alerts, the suppression must be scoped to the specific CVE being handled, not the entire dependency, so that other CVEs affecting the same dependency continue to be flagged.