fix(security): T2.1 hardening: cap Tika input stream at 100 MB (issue #92) - #93
Merged
Merged
Conversation
…92) Defense-in-depth for the 15 CVEs in commons-tika 2.9.x (the latest 1.8-compatible line; no upstream fix is possible without leaving Java 1.8). The CVEs are mostly DoS / zip-bomb style in the parser tree; closing them requires either a library upgrade (not available for 1.8) or defensive code patterns in the few call sites. This PR caps the input stream at 100 MB (overridable via the system property PSARCHIVE_MAX_TIKA_INPUT_BYTES) so that an attacker-controlled file is rejected before Tika's parsers see it. What's new: - PSTikaCap: a small utility class in modules/perc-security-utils (com.percussion.security.io.PSTikaCap) that wraps an InputStream with a hard byte cap. After the configured cap is reached, the stream returns EOF. Tika handles the EOF gracefully (returns a short parsed result rather than OOM or hanging). - Default cap: 100 MB (100L << 20). Override via system property PSARCHIVE_MAX_TIKA_INPUT_BYTES (same naming convention as the other caps in PSArchiveFiles and PSZipBombGuard). Applied at the 2 production parse sites: - system/.../PSTikaTextConvertor.java: caps the Tika input in getConvertedText (the main entry point for the Lucene indexer). Untrusted file content reaches this method via the standard file-upload flow. - system/services/.../PSDbStorageService.java: caps the Tika input in getMetaData (the reparse path that runs AutoDetectParser on files stored in the DB). Not applied at the mime-detection sites (AssetsResource, PSDbStorageService detection half). Those use TikaConfig.getDetector().detect() which only reads the first few KB to sniff the magic bytes — small attack surface that doesn't warrant a cap. Total diff: 3 files, +106 / -2. Verification: - ./mvn-env.sh clean install -DskipTests: BUILD SUCCESS in 3:50 (61 modules, Java 1.8.0_504) - No UnsupportedClassVersionError in the build log - Both hardened files already had perc-security-utils as a dep (they use the security utilities elsewhere), so no module-pom changes were required Out of scope (separate issues): - commons-httpclient 3.1 -> HttpClient 5 (issue #88, deferred) - T2.4 Spring + Spring Security hardening (45+ CVEs) - T2.13 Eclipse Jetty hardening (29+ CVEs) Refs #92, #73, #72
natechadwick
approved these changes
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
T2.1 hardening sub-task of the parent epic #73. This is defense-in-depth for the 15 CVEs in commons-tika 2.9.x (the latest 1.8-compatible line; no upstream fix is available without leaving Java 1.8). The CVEs are mostly DoS / zip-bomb style in the parser tree; closing them requires either a library upgrade (not available for 1.8) or defensive code patterns in the few call sites.
This PR caps the input stream at 100 MB (overridable via the system property
PSARCHIVE_MAX_TIKA_INPUT_BYTES) so that an attacker-controlled file is rejected before Tika's parsers see it.What changes (3 files, +106 / −2)
1. New utility class (1 file, +101)
modules/perc-security-utils/src/main/java/com/percussion/security/io/PSTikaCap.java— wraps anInputStreamwith a hard byte cap. After the configured cap is reached, the stream returns EOF. Tika handles the EOF gracefully (returns a short parsed result rather than OOM or hanging). Default cap: 100 MB (100L << 20). Override viaPSARCHIVE_MAX_TIKA_INPUT_BYTES.The class is a simple
FilterInputStreamsubclass (no buffering); the overhead is one counter perreadcall.2. Applied at the 2 production parse sites (2 files, +6 / −2)
system/.../PSTikaTextConvertor.javagetConvertedText— the main entry point for the Lucene indexer. Untrusted file content reaches this method via the standard file-upload flow. The output side is already capped via the existingWriteOutContentHandler(writeLimit)(5M chars default).system/services/.../PSDbStorageService.javagetMetaData— the reparse path that runsAutoDetectParseron files stored in the DB.Each call site change is one line:
What's NOT hardened (explicit out-of-scope)
AssetsResource.javaand the detection half ofPSDbStorageService.javauseTikaConfig.getDetector().detect()which only reads the first few KB to sniff the magic bytes — small attack surface, doesn't need a cap.PSMeta.java,PSBinary.java,ProxyInputStream.javaare just type definitions / stream helpers — not parse sites.Verification
./mvn-env.sh clean install -DskipTests→ BUILD SUCCESS in 3:50 (61 modules, Java 1.8.0_504)UnsupportedClassVersionErrorin the build logperc-security-utilsas a dep (they use the security utilities elsewhere), so no module-pom changes were requiredManual smoke test (recommended before merge)
Build a 200 MB test file and pass it to
PSTikaTextConvertor.getConvertedText:parser.parse()completes successfully (with a short parsed result, not OOM)The override mechanism can be exercised by setting
-DPSARCHIVE_MAX_TIKA_INPUT_BYTES=1048576(1 MB) and re-running the same test.Out of scope (separate issues under #73)
commons-httpclient 3.1 → HttpClient 5(issue deps: EOL replace commons-httpclient 3.1 with org.apache.httpcomponents.client5:httpclient5 (closes 1 CVE) #88, deferred; multi-day migration across 29 files)commons-beanutils 1.11.0 → beanutils2EOL (issue deps: EOL replace commons-beanutils 1.11.0 with commons-beanutils2 2.0.0 (closes 3 CVEs + drops transitive SnakeYAML 16 CVEs) #91, closed; the 1.x line is still maintained)StringSubstitutorwhich the project doesn't use) — N/Acommons-configuration 1.10(project doesn't use it) — N/AReferences
docs/ai-generated/tasks/PR#-DependencyVulnerabilityAnalysis/issues/02-epic-non-upgradeable.md#t21--apache-tika-29x-hardeningPSZipBombGuard(same defensive-hardening pattern, from PR fix(security): T2.6 hardening: zip-bomb size caps on the remaining zip sites (issue #89) #90):com.percussion.security.io.PSZipBombGuard