Skip to content

fix(security): upgrade vulnerable dependencies and add OWASP suppressions#35236

Merged
dsilvam merged 7 commits intomainfrom
fix/security-owasp-dependency-upgrades-35235
Apr 14, 2026
Merged

fix(security): upgrade vulnerable dependencies and add OWASP suppressions#35236
dsilvam merged 7 commits intomainfrom
fix/security-owasp-dependency-upgrades-35235

Conversation

@mbiuki
Copy link
Copy Markdown
Contributor

@mbiuki mbiuki commented Apr 7, 2026

Summary

Addresses OWASP Dependency Check findings reported by a customer (tracked in #35235).

  • Upgrades 5 libraries with genuine CVE exposure in dotCMS's usage
  • Adds OWASP suppressions for 21 false-positive / non-applicable CVEs
  • Fixes compilation breakage in 8 test files caused by Files.createTempDir() removal in guava 32.0.1-jre

Changes

bom/application/pom.xml — Dependency version upgrades

Library Old Version New Version CVE(s) Fixed CVSS
commons-beanutils 1.9.4 1.11.0 CVE-2025-48734 8.8 HIGH
commons-io 2.11.0 2.14.0 CVE-2024-47554 4.3 MEDIUM
guava 27.0.1-android 32.0.1-jre CVE-2023-2976, CVE-2020-8908 7.1 / 3.3
bouncy-castle.version (bcprov-jdk15on) 1.70 1.73 CVE-2023-33202 5.5 MEDIUM
commons-lang3 3.12.0 3.18.0 CVE-2025-48924 5.3 MEDIUM

Note on guava: switched from -android to -jre variant — the android build was inappropriate for a server JVM.

owasp-suppressions.xml — False-positive suppressions

Elasticsearch (16 CVEs): All flagged CVEs are server-process vulnerabilities (node memory, ingest pipelines, audit logging, PKI realm). dotCMS ships only the elasticsearch-rest-high-level-client JAR; the server code paths do not exist in the classpath.

dot.struts (5 CVEs):

Test file fixes — Files.createTempDir() removed in guava 32.0.1-jre

com.google.common.io.Files.createTempDir() was removed in guava 32.0.1-jre (deprecated since 30.0). Migrated 8 test files to java.nio.file.Files.createTempDirectory():

File Notes
ZipUtilTest.java Already had NIO import; replaced 2 fully-qualified guava calls
H22CacheTest.java Wrapped NIO call in try/catch (enclosing method has no throws)
ESContentletAPIImplTest.java Swapped guava import → NIO
StaticPushPublishBundleGeneratorTest.java Swapped guava import → NIO
ThemeDataGen.java Swapped guava import → NIO
VTLResourceIntegrationTest.java Swapped guava import → NIO
TestDataUtils.java Swapped guava import → NIO; 5 call sites (all inside catch (Exception e) blocks)
BinaryToMapTransformerTest.java Swapped guava import → NIO; 2 call sites

Test Plan

  • Run ./mvnw install -pl :dotcms-core -DskipTests to verify the project compiles cleanly with new versions
  • Run OWASP Dependency Check scan and confirm suppressed CVEs no longer appear in the report
  • Smoke-test content management, search (Elasticsearch client), and SAML/JWT flows (BouncyCastle) in a dev environment
  • Run integration tests for affected areas: ZipUtilTest, H22CacheTest, ESContentletAPIImplTest, BinaryToMapTransformerTest

Notes

  • dot.commons-io and dot.guava are custom-repackaged artifacts managed separately — those require a separate repackaging task
  • Customers running their own Elasticsearch 7.10.2 cluster should upgrade the cluster to 7.17.25+ independently

Closes #35235

…ions (fixes #35235)

Upgrades flagged by OWASP Dependency Check customer report:
- commons-beanutils 1.9.4 → 1.11.0 (CVE-2025-48734, CVSS 8.8 RCE)
- commons-io 2.11.0 → 2.14.0 (CVE-2024-47554, CVSS 4.3 DoS)
- guava 27.0.1-android → 32.0.1-jre (CVE-2023-2976, CVE-2020-8908)
- bcprov-jdk15on 1.70 → 1.73 via bouncy-castle.version property (CVE-2023-33202)
- commons-lang3 3.12.0 → 3.18.0 (CVE-2025-48924)

Also adds OWASP suppressions for 21 false-positive/non-applicable CVEs:
- 16 Elasticsearch server-side CVEs (dotCMS ships client JARs only)
- 5 dot.struts CVEs (3 are Struts 2 misattributions; 2 XStream CVEs not
  exploitable in dotCMS's JSP/Tiles-only usage of Struts 1.x)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 7, 2026

mbiuki and others added 2 commits April 7, 2026 12:03
Files.createTempDir() was removed in guava 32.0.1-jre (deprecated since 30.0).
Replace all usages in test code with java.nio.file.Files.createTempDirectory()
to restore compilation after the guava upgrade in the preceding commit.

Files changed:
- H22CacheTest: wrap NIO call in try/catch since method doesn't declare throws
- ZipUtilTest: already imported java.nio.file.Files, use it directly
- 6 integration test files: swap guava import for java.nio.file.Files and
  update call sites (all enclosing methods throw Exception/IOException)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
commons-io 2.14.0: IOUtils.readLines(Reader) no longer declares throws IOException
— removed the now-dead try/catch in CSVManifestReader.init(Reader)

guava 32.0.1-jre: introduces checker-qual as a transitive dependency which is
banned in this project — added exclusion in bom/application/pom.xml

Also reverts bcprov-jdk15on back to 1.70: bcprov 1.73 is not yet published to
the dotCMS Artifactory (libs-release). This upgrade requires the artifact to be
added to Artifactory before it can be applied.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 7, 2026

Test Results

Compilation

./mvnw test-compile -pl :dotcms-core -DskipTests — ✅ BUILD SUCCESS

Two compile issues were found and fixed during this process (both caused by the dependency upgrades):

1. CSVManifestReader.java — commons-io 2.14.0 API change
IOUtils.readLines(Reader) no longer declares throws IOException in commons-io 2.14.0. The existing try/catch became dead code, which Java treats as a compile error. Fixed by removing the redundant try/catch block.

2. guava 32.0.1-jre — banned transitive dependency
Guava 32.x introduces org.checkerframework:checker-qual as a transitive dependency, which is explicitly banned in this project's Maven enforcer rules. Fixed by adding an exclusion in bom/application/pom.xml.

3. bcprov-jdk15on 1.73 — not available in dotCMS Artifactory
The dotCMS Artifactory (libs-release) only has BouncyCastle up to version 1.70. The upgrade to 1.73 was reverted. This will require adding the artifact to Artifactory before it can be applied — tracked in #35235.


Unit Tests

Ran ZipUtilTest and H22CacheTest — the two unit tests directly affected by the guava Files.createTempDir() migration:

[INFO] Running com.dotmarketing.util.ZipUtilTest
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.309 s ✅

[INFO] Running com.dotmarketing.business.cache.provider.h22.H22CacheTest
[INFO] Tests run: 11, Failures: 0, Errors: 0, Skipped: 7, Time elapsed: 42.79 s ✅

Results: Tests run: 14, Failures: 0, Errors: 0, Skipped: 7
BUILD SUCCESS

The 7 skipped tests in H22CacheTest are pre-existing @Ignore-annotated tests unrelated to these changes.


Integration Tests

The integration tests (ESContentletAPIImplTest, BinaryToMapTransformerTest, StaticPushPublishBundleGeneratorTest, VTLResourceIntegrationTest, TestDataUtils, ThemeDataGen, ContentletTransformerTest) require a running PostgreSQL + Elasticsearch environment and cannot be run locally without infrastructure. These should be validated by CI once the PR is merged to a test environment.

Changes to those files are mechanical (Files.createTempDir()Files.createTempDirectory("dotcms-test").toFile()) with no logic change.

@mbiuki mbiuki requested a review from wezell April 7, 2026 22:06
@mbiuki mbiuki moved this to Next Sprint in dotCMS - Product Planning Apr 7, 2026
@mbiuki mbiuki self-assigned this Apr 7, 2026
Copy link
Copy Markdown
Member

@wezell wezell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch will need smoke tests - make sure we have not broken the struts action paths and CSV import process.

…r dependency upgrades

Addresses wezell's review comment on PR #35236: verify that the
commons-beanutils 1.9.4→1.11.0 and commons-io 2.11.0→2.14.0 upgrades
have not broken the Struts-based CSV import path.

Two test groups in ImportContentletsActionSmokeTest:
1. Struts form binding — exercises BeanUtils.populate() against
   ImportContentletsForm to confirm String/long/String[] conversions
   still work correctly under commons-beanutils 1.11.0.
2. CSV import pipeline — calls ImportUtil.importFile() in preview mode,
   replicating the ImportContentletsAction._generatePreview() code path,
   and asserts a clean result with no errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 13, 2026

Smoke Test Results — Struts Action Paths & CSV Import

Addressing @wezell's review: "make sure we have not broken the struts action paths and CSV import process."


What was added

New test class committed in this branch:
dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/action/ImportContentletsActionSmokeTest.java

Group 1 — Struts form binding (2 tests)

These directly validate that commons-beanutils 1.11.0 still correctly populates ImportContentletsForm the way Struts does it via BeanUtils.populate():

Test What it verifies
strutsFormBinding_populatesAllFieldsViaBeansUtils String, long, and String[] field conversions all work correctly
strutsFormBinding_singleFieldConvertedToArray Single-value String input for a String[] field is correctly wrapped into a one-element array (single key field case)

Group 2 — CSV import pipeline (1 test)

Test What it verifies
csvImportPipeline_previewSucceedsWithNoErrors Calls ImportUtil.importFile() in preview mode via a CsvReader — the same code path ImportContentletsAction._generatePreview() follows — and asserts zero errors, confirming the commons-io 2.14.0 and guava 32.0.1-jre upgrades have not broken CSV parsing

Local run status

Local execution was blocked by environment constraints:

  • Integration tests require a dotCMS license (~/.dotcms/license/license.zip or DOT_DOTCMS_LICENSE env var) — not available on this machine
  • The pre-integration-test Ant task (cleanup-it-test-data) fails before tests start without it

The tests are committed to the branch (dbcdedbe0d) and will be validated by CI on the next run.

To run manually once the environment is set up:

sdk env   # activate JDK 21 via SDKMAN
./mvnw verify -pl :dotcms-integration \
  -Dcoreit.test.skip=false \
  -Dit.test=ImportContentletsActionSmokeTest \
  -Dopensearch.upgrade.test=true

@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 14, 2026

Smoke Test Results — Struts Action Paths & CSV Import ✅

Addressing @wezell's review: "make sure we have not broken the struts action paths and CSV import process."


Results

All 3 tests passedImportContentletsActionSmokeTest
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 25.24 s

Test Area Result
strutsFormBinding_populatesAllFieldsViaBeansUtils Struts form binding ✅ PASS
strutsFormBinding_singleFieldConvertedToArray Struts form binding ✅ PASS
csvImportPipeline_previewSucceedsWithNoErrors CSV import pipeline ✅ PASS

What each test validates

Struts form binding (2 tests)

  • BeanUtils.populate() correctly binds String, long, and String[] fields on ImportContentletsForm — exactly what Struts does internally when the user submits the import portlet form
  • Confirms that the commons-beanutils 1.9.4 → 1.11.0 upgrade has not broken form field conversion for the CSV import action path

CSV import pipeline (1 test)

  • Calls ImportUtil.importFile() in preview mode via a live CsvReader, replicating the ImportContentletsAction._generatePreview() code path end-to-end
  • Asserts zero errors on a valid 2-row CSV — confirms that the commons-io 2.11.0 → 2.14.0 and guava 27.0.1-android → 32.0.1-jre upgrades have not broken CSV parsing or the import pipeline

Run environment: JDK 21.0.8-ms · Maven · PostgreSQL (pgvector/pgvector:pg18) · OpenSearch 1.3.6 · Total build time: 8m 44s

@mbiuki mbiuki requested a review from wezell April 14, 2026 14:29
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 14, 2026

@wezell smoke tests for the Struts action paths and CSV import process are done and passing (see results above). Could you take another look when you get a chance? Thanks!

Copy link
Copy Markdown
Member

@wezell wezell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking better, thanks @mbiuki

Copy link
Copy Markdown
Member

@wezell wezell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, make sure to add this new test to the testing suite - it won't run unless it is in there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 14, 2026

Hey @wezell — done! I've added ImportContentletsActionSmokeTest to MainSuite3a as you requested. The commit is pushed to the branch. Let me know if anything else needs to be addressed.

Copy link
Copy Markdown
Member

@wezell wezell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, good stuff

@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 14, 2026

Hey @spbolton — I noticed something while working on this PR that I wanted to check with you about.

In parent/pom.xml at line 1927, there's a reference to a suppression file:

<suppressionFile>dependency-check-suppressions.xml</suppressionFile>

This reference was added in commit 62e8d60061 (PR #27461, Feb 23, 2024), but the file dependency-check-suppressions.xml has never actually been created in the repo.

As part of this PR I added owasp-suppressions.xml with suppressions for Elasticsearch and Struts false positives, but I realize it won't be picked up by the plugin because the filename doesn't match what parent/pom.xml expects.

Could you clarify:

  1. Was dependency-check-suppressions.xml supposed to be created as part of PR chore(maven) Cleanup maven docker processes including postman #27461 but got missed?
  2. Should I rename owasp-suppressions.xmldependency-check-suppressions.xml to wire it up correctly?

Want to make sure I'm not missing something before making any changes. Thanks!

@dsilvam dsilvam added this pull request to the merge queue Apr 14, 2026
github-merge-queue bot pushed a commit that referenced this pull request Apr 14, 2026
…ions (#35236)

## Summary

Addresses OWASP Dependency Check findings reported by a customer
(tracked in #35235).

- Upgrades 5 libraries with genuine CVE exposure in dotCMS's usage
- Adds OWASP suppressions for 21 false-positive / non-applicable CVEs
- Fixes compilation breakage in 8 test files caused by
`Files.createTempDir()` removal in guava 32.0.1-jre

## Changes

### `bom/application/pom.xml` — Dependency version upgrades

| Library | Old Version | New Version | CVE(s) Fixed | CVSS |
|---|---|---|---|---|
| `commons-beanutils` | 1.9.4 | **1.11.0** | CVE-2025-48734 | 8.8 HIGH |
| `commons-io` | 2.11.0 | **2.14.0** | CVE-2024-47554 | 4.3 MEDIUM |
| `guava` | 27.0.1-android | **32.0.1-jre** | CVE-2023-2976,
CVE-2020-8908 | 7.1 / 3.3 |
| `bouncy-castle.version` (bcprov-jdk15on) | 1.70 | **1.73** |
CVE-2023-33202 | 5.5 MEDIUM |
| `commons-lang3` | 3.12.0 | **3.18.0** | CVE-2025-48924 | 5.3 MEDIUM |

Note on guava: switched from `-android` to `-jre` variant — the android
build was inappropriate for a server JVM.

### `owasp-suppressions.xml` — False-positive suppressions

**Elasticsearch (16 CVEs):** All flagged CVEs are server-process
vulnerabilities (node memory, ingest pipelines, audit logging, PKI
realm). dotCMS ships only the `elasticsearch-rest-high-level-client`
JAR; the server code paths do not exist in the classpath.

**dot.struts (5 CVEs):**
- CVE-2012-0391, CVE-2023-34396, CVE-2023-34149 — these are **Struts 2**
CVEs misattributed by Dependency Check to the Struts 1.x JAR (Struts 1.x
has no OGNL parameter handling)
- CVE-2020-26258, CVE-2020-26259 — XStream SSRF/file-deletion; dotCMS
uses Struts for JSP/Tiles rendering only (no XStream deserialization);
CVE-2020-26259 also requires Java < 15

### Test file fixes — `Files.createTempDir()` removed in guava
32.0.1-jre

`com.google.common.io.Files.createTempDir()` was removed in guava
32.0.1-jre (deprecated since 30.0). Migrated 8 test files to
`java.nio.file.Files.createTempDirectory()`:

| File | Notes |
|---|---|
| `ZipUtilTest.java` | Already had NIO import; replaced 2
fully-qualified guava calls |
| `H22CacheTest.java` | Wrapped NIO call in try/catch (enclosing method
has no `throws`) |
| `ESContentletAPIImplTest.java` | Swapped guava import → NIO |
| `StaticPushPublishBundleGeneratorTest.java` | Swapped guava import →
NIO |
| `ThemeDataGen.java` | Swapped guava import → NIO |
| `VTLResourceIntegrationTest.java` | Swapped guava import → NIO |
| `TestDataUtils.java` | Swapped guava import → NIO; 5 call sites (all
inside `catch (Exception e)` blocks) |
| `BinaryToMapTransformerTest.java` | Swapped guava import → NIO; 2 call
sites |

## Test Plan

- [ ] Run `./mvnw install -pl :dotcms-core -DskipTests` to verify the
project compiles cleanly with new versions
- [ ] Run OWASP Dependency Check scan and confirm suppressed CVEs no
longer appear in the report
- [ ] Smoke-test content management, search (Elasticsearch client), and
SAML/JWT flows (BouncyCastle) in a dev environment
- [ ] Run integration tests for affected areas: `ZipUtilTest`,
`H22CacheTest`, `ESContentletAPIImplTest`, `BinaryToMapTransformerTest`

## Notes

- `dot.commons-io` and `dot.guava` are custom-repackaged artifacts
managed separately — those require a separate repackaging task
- Customers running their own Elasticsearch 7.10.2 cluster should
upgrade the cluster to 7.17.25+ independently

Closes #35235

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 14, 2026
@dsilvam dsilvam added this pull request to the merge queue Apr 14, 2026
Merged via the queue into main with commit 2898525 Apr 14, 2026
49 checks passed
@dsilvam dsilvam deleted the fix/security-owasp-dependency-upgrades-35235 branch April 14, 2026 20:52
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 15, 2026

Hey @spbolton — I noticed something while working on this PR that I wanted to check with you about.

In parent/pom.xml at line 1927, there's a reference to a suppression file:

<suppressionFile>dependency-check-suppressions.xml</suppressionFile>

This reference was added in commit 62e8d60061 (PR #27461, Feb 23, 2024), but the file dependency-check-suppressions.xml has never actually been created in the repo.

As part of this PR I added owasp-suppressions.xml with suppressions for Elasticsearch and Struts false positives, but I realize it won't be picked up by the plugin because the filename doesn't match what parent/pom.xml expects.

Could you clarify:

  1. Was dependency-check-suppressions.xml supposed to be created as part of PR chore(maven) Cleanup maven docker processes including postman #27461 but got missed?
  2. Should I rename owasp-suppressions.xmldependency-check-suppressions.xml to wire it up correctly?

Want to make sure I'm not missing something before making any changes. Thanks!

@dsilvam Is this ok? I know this is merged, but do we have to create a new ticket to fix this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Next Sprint

Development

Successfully merging this pull request may close these issues.

fix(security): Upgrade vulnerable dependencies flagged by OWASP Dependency Check

3 participants