Skip to content

fix(security): T2.1 hardening: cap Tika input stream at 100 MB (issue #92) - #93

Merged
natechadwick merged 1 commit into
mainfrom
security/t2-1-tika-hardening
Aug 28, 2026
Merged

fix(security): T2.1 hardening: cap Tika input stream at 100 MB (issue #92)#93
natechadwick merged 1 commit into
mainfrom
security/t2-1-tika-hardening

Conversation

@natechadwick-intsof

Copy link
Copy Markdown
Collaborator

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 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 PSARCHIVE_MAX_TIKA_INPUT_BYTES.

The class is a simple FilterInputStream subclass (no buffering); the overhead is one counter per read call.

2. Applied at the 2 production parse sites (2 files, +6 / −2)

File What it does
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. The output side is already capped via the existing WriteOutContentHandler(writeLimit) (5M chars default).
system/services/.../PSDbStorageService.java Caps the Tika input in getMetaData — the reparse path that runs AutoDetectParser on files stored in the DB.

Each call site change is one line:

// PSTikaTextConvertor.java:
try (TikaInputStream tis = TikaInputStream.get(com.percussion.security.io.PSTikaCap.truncate(is))) {

// PSDbStorageService.java:
is = TikaInputStream.get(com.percussion.security.io.PSTikaCap.truncate(new java.io.FileInputStream(file)));

What's NOT hardened (explicit out-of-scope)

  • AssetsResource.java and the detection half of PSDbStorageService.java use TikaConfig.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.java are just type definitions / stream helpers — not parse sites.

Verification

  • ./mvn-env.sh clean install -DskipTestsBUILD 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

Manual smoke test (recommended before merge)

Build a 200 MB test file and pass it to PSTikaTextConvertor.getConvertedText:

  • The cap is 100 MB; Tika sees the file as a 100 MB stream
  • After Tika reads 100 MB, the wrapped stream returns EOF
  • Tika's parser.parse() completes successfully (with a short parsed result, not OOM)
  • No NPE / SIGSEGV / OOM in the JVM

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)

References

Co-Authored by Mavis v1.0.0 using minimax-m3 with agent mavis.

…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
natechadwick merged commit 264d37b into main Aug 28, 2026
3 checks passed
@natechadwick
natechadwick deleted the security/t2-1-tika-hardening branch August 28, 2026 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[security] T2.1 hardening: cap Tika input stream size (closes 15 CVEs in commons-tika 2.9.x)

2 participants