This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new 64deef8cb6 improve depth limits (#3319)
64deef8cb6 is described below

commit 64deef8cb69fc8a0c56dd28a4bdef71b794203a3
Author: Tim Allison <[email protected]>
AuthorDate: Mon Oct 12 12:47:16 2026 -0400

    improve depth limits (#3319)
---
 .../ROOT/pages/advanced/setting-limits.adoc        | 11 +++---
 .../pages/migration-to-4x/migrating-to-4x.adoc     | 10 +++++
 .../org/apache/tika/config/EmbeddedLimits.java     |  6 ++-
 .../java/org/apache/tika/config/OutputLimits.java  | 46 +++++++++++++++-------
 .../apache/tika/parser/RecursiveParserWrapper.java | 37 ++++++++++++++++-
 .../org/apache/tika/sax/SecureContentHandler.java  | 28 +++++++++++--
 .../apache/tika/sax/SecureContentHandlerTest.java  |  2 +-
 .../tika/parser/RecursiveParserWrapperTest.java    | 23 +++++++++++
 .../tika/parser/pkg/CompressorParserTest.java      |  6 +--
 .../org/apache/tika/parser/pkg/ZipParserTest.java  |  9 ++---
 .../java/org/apache/tika/config/AllLimitsTest.java |  2 +-
 .../org/apache/tika/config/EmbeddedLimitsTest.java |  6 +--
 .../org/apache/tika/config/OutputLimitsTest.java   |  2 +-
 .../apache/tika/config/loader/TikaLoaderTest.java  |  4 +-
 14 files changed, 146 insertions(+), 46 deletions(-)

diff --git a/docs/modules/ROOT/pages/advanced/setting-limits.adoc 
b/docs/modules/ROOT/pages/advanced/setting-limits.adoc
index 2f8c208cf6..957fe2e9e1 100644
--- a/docs/modules/ROOT/pages/advanced/setting-limits.adoc
+++ b/docs/modules/ROOT/pages/advanced/setting-limits.adoc
@@ -30,7 +30,7 @@ throughout the parse.
 
 |`embedded-limits`
 |`EmbeddedLimits`
-|Depth and count of embedded documents. Unlimited by default.
+|Depth and count of embedded documents. Depth 20, count unlimited by default.
 
 |`output-limits`
 |`OutputLimits`
@@ -74,7 +74,6 @@ these but `exception-reporting`, which has its own test:
       "writeLimit": 100000,
       "throwOnWriteLimit": false,
       "maxXmlDepth": 100,
-      "maxPackageEntryDepth": 10,
       "zipBombThreshold": 1000000,
       "zipBombRatio": 100
     },
@@ -131,7 +130,7 @@ Tests: `AllLimitsTest`, `EmbeddedLimitsTest`, 
`OutputLimitsTest`, `TimeoutLimits
 |Setting |Default |Description
 
 |`maxDepth`
-|-1 (unlimited)
+|20
 |Maximum nesting depth. Recursion stops at the limit; siblings at the current
 level still parse.
 
@@ -184,8 +183,10 @@ container.zip (depth 0)
 |Maximum XML element nesting depth. Guards against XML bombs.
 
 |`maxPackageEntryDepth`
-|10
-|Maximum depth of nested package entries (zip within zip).
+|20
+|Deprecated in 4.2, removed in 4.3; use `embedded-limits` `maxDepth`, which
+bounds nesting on every path. Counts nested package entries only when embedded
+content is inlined into its container's XHTML.
 
 |`zipBombThreshold`
 |1,000,000
diff --git a/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc 
b/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
index 28b7fd7d44..3b57b0e67e 100644
--- a/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
+++ b/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
@@ -268,6 +268,16 @@ Configure the engine under `engines` and name it in 
`text-recognizers` (or bind
 excluding `pdf-parser` goes with it: the 4.2 shape is `"pages": {"text": 
"OCR"}` with the
 VLM as recognizer, which sends rendered pages rather than the file.
 
+=== Embedded depth defaults and `maxPackageEntryDepth` deprecated (4.2.0+)
+
+`embedded-limits` `maxDepth` defaults to 20 (was unlimited) on every path. 
`output-limits`
+`maxPackageEntryDepth` is deprecated and removed in 4.3.0, after which a 
config that sets it
+fails to load; it logs a WARN when set. Until then it defaults to 20 (was 10, 
which allowed
+only 9 levels). A concatenated parse of a deeply nested archive now stops at 
depth 20 and sets
+`tk:exception:embedded-depth-limit-reached` instead of throwing. The zip-bomb 
ratio now
+applies across the whole document tree on the `/rmeta` path, as it already did 
on the
+concatenated path, and fails the parse with `Zip bomb detected!`.
+
 === Embedding filters and the image embedding parser deprecated (4.1.0+)
 
 `openai-embedding-filter`, `jina-embedding-filter` and 
`openai-image-embedding-parser` are
diff --git a/tika-core/src/main/java/org/apache/tika/config/EmbeddedLimits.java 
b/tika-core/src/main/java/org/apache/tika/config/EmbeddedLimits.java
index 4bf8f86341..653e553421 100644
--- a/tika-core/src/main/java/org/apache/tika/config/EmbeddedLimits.java
+++ b/tika-core/src/main/java/org/apache/tika/config/EmbeddedLimits.java
@@ -25,7 +25,7 @@ import org.apache.tika.parser.ParseContext;
  * <p>
  * This controls how deep and how many embedded documents are processed:
  * <ul>
- *   <li>{@code maxDepth} - maximum nesting depth for embedded documents (-1 = 
unlimited)</li>
+ *   <li>{@code maxDepth} - maximum nesting depth for embedded documents 
(default: 20, -1 = unlimited)</li>
  *   <li>{@code throwOnMaxDepth} - whether to throw an exception when maxDepth 
is reached</li>
  *   <li>{@code maxCount} - maximum number of embedded documents to process 
(-1 = unlimited)</li>
  *   <li>{@code throwOnMaxCount} - whether to throw an exception when maxCount 
is reached</li>
@@ -74,7 +74,9 @@ public class EmbeddedLimits implements Serializable {
 
     public static final int UNLIMITED = -1;
 
-    private int maxDepth = UNLIMITED;
+    public static final int DEFAULT_MAX_DEPTH = 20;
+
+    private int maxDepth = DEFAULT_MAX_DEPTH;
     private boolean throwOnMaxDepth = false;
     private int maxCount = UNLIMITED;
     private boolean throwOnMaxCount = false;
diff --git a/tika-core/src/main/java/org/apache/tika/config/OutputLimits.java 
b/tika-core/src/main/java/org/apache/tika/config/OutputLimits.java
index 46ebad5c76..0e7bd540b9 100644
--- a/tika-core/src/main/java/org/apache/tika/config/OutputLimits.java
+++ b/tika-core/src/main/java/org/apache/tika/config/OutputLimits.java
@@ -17,6 +17,9 @@
 package org.apache.tika.config;
 import java.io.Serializable;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import org.apache.tika.annotation.TikaComponent;
 import org.apache.tika.parser.ParseContext;
 
@@ -28,7 +31,7 @@ import org.apache.tika.parser.ParseContext;
  *   <li>{@code writeLimit} - maximum characters to write (-1 = unlimited)</li>
  *   <li>{@code throwOnWriteLimit} - whether to throw an exception when 
writeLimit is reached</li>
  *   <li>{@code maxXmlDepth} - maximum XML element nesting depth (default: 
100)</li>
- *   <li>{@code maxPackageEntryDepth} - maximum package entry nesting depth 
(default: 10)</li>
+ *   <li>{@code maxPackageEntryDepth} - deprecated; use {@link 
EmbeddedLimits#setMaxDepth(int)}</li>
  *   <li>{@code zipBombThreshold} - characters before zip bomb check activates 
(default: 1,000,000)</li>
  *   <li>{@code zipBombRatio} - maximum output:input ratio for zip bomb 
detection (default: 100)</li>
  * </ul>
@@ -40,7 +43,7 @@ import org.apache.tika.parser.ParseContext;
  *   <li>If {@code throwOnWriteLimit=true}: {@code WriteLimitReachedException} 
is thrown</li>
  * </ul>
  * <p>
- * <b>Security limits:</b> maxXmlDepth, maxPackageEntryDepth, and zipBomb
+ * <b>Security limits:</b> maxXmlDepth and zipBomb
  * limits always throw exceptions when exceeded (no silent truncation option).
  * <p>
  * Example configuration:
@@ -51,8 +54,7 @@ import org.apache.tika.parser.ParseContext;
  *       "writeLimit": 100000,
  *       "throwOnWriteLimit": false,
  *       "maxXmlDepth": 100,
- *       "maxPackageEntryDepth": 10,
- *       "zipBombThreshold": 1000000,
+ * *       "zipBombThreshold": 1000000,
  *       "zipBombRatio": 100
  *     }
  *   }
@@ -66,6 +68,8 @@ public class OutputLimits implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(OutputLimits.class);
+
     public static final int UNLIMITED = -1;
 
     // Output limits
@@ -74,7 +78,7 @@ public class OutputLimits implements Serializable {
 
     // XML/Security limits
     private int maxXmlDepth = 100;
-    private int maxPackageEntryDepth = 10;
+    private int maxPackageEntryDepth = 20;
     private long zipBombThreshold = 1_000_000;
     private long zipBombRatio = 100;
 
@@ -90,21 +94,31 @@ public class OutputLimits implements Serializable {
      * @param writeLimit maximum characters to write (-1 = unlimited)
      * @param throwOnWriteLimit whether to throw when write limit is reached
      * @param maxXmlDepth maximum XML element nesting depth
-     * @param maxPackageEntryDepth maximum package entry nesting depth
      * @param zipBombThreshold characters before zip bomb check activates
      * @param zipBombRatio maximum output:input ratio
      */
-    public OutputLimits(int writeLimit, boolean throwOnWriteLimit,
-                        int maxXmlDepth, int maxPackageEntryDepth,
+    public OutputLimits(int writeLimit, boolean throwOnWriteLimit, int 
maxXmlDepth,
                         long zipBombThreshold, long zipBombRatio) {
         this.writeLimit = writeLimit;
         this.throwOnWriteLimit = throwOnWriteLimit;
         this.maxXmlDepth = maxXmlDepth;
-        this.maxPackageEntryDepth = maxPackageEntryDepth;
         this.zipBombThreshold = zipBombThreshold;
         this.zipBombRatio = zipBombRatio;
     }
 
+    /**
+     * @deprecated package-entry depth only bounds nesting when embedded 
content is
+     * inlined into its container's XHTML; use {@link 
EmbeddedLimits#setMaxDepth(int)},
+     * which bounds nesting on every path. To be removed in 4.3.
+     */
+    @Deprecated(since = "4.2", forRemoval = true)
+    public OutputLimits(int writeLimit, boolean throwOnWriteLimit,
+                        int maxXmlDepth, int maxPackageEntryDepth,
+                        long zipBombThreshold, long zipBombRatio) {
+        this(writeLimit, throwOnWriteLimit, maxXmlDepth, zipBombThreshold, 
zipBombRatio);
+        setMaxPackageEntryDepth(maxPackageEntryDepth);
+    }
+
     /**
      * Gets the maximum characters to write.
      *
@@ -160,20 +174,22 @@ public class OutputLimits implements Serializable {
     }
 
     /**
-     * Gets the maximum package entry nesting depth.
-     *
-     * @return maximum package entry depth
+     * @deprecated use {@link EmbeddedLimits#getMaxDepth()}. To be removed in 
4.3.
      */
+    @Deprecated(since = "4.2", forRemoval = true)
     public int getMaxPackageEntryDepth() {
         return maxPackageEntryDepth;
     }
 
     /**
-     * Sets the maximum package entry nesting depth.
-     *
-     * @param maxPackageEntryDepth maximum package entry depth
+     * @deprecated package-entry depth only bounds nesting when embedded 
content is
+     * inlined into its container's XHTML; use {@link 
EmbeddedLimits#setMaxDepth(int)},
+     * which bounds nesting on every path. To be removed in 4.3.
      */
+    @Deprecated(since = "4.2", forRemoval = true)
     public void setMaxPackageEntryDepth(int maxPackageEntryDepth) {
+        LOG.warn("maxPackageEntryDepth is deprecated and will be removed in 
4.3; " +
+                "use embedded-limits maxDepth");
         this.maxPackageEntryDepth = maxPackageEntryDepth;
     }
 
diff --git 
a/tika-core/src/main/java/org/apache/tika/parser/RecursiveParserWrapper.java 
b/tika-core/src/main/java/org/apache/tika/parser/RecursiveParserWrapper.java
index c905bfba22..24fadc464d 100644
--- a/tika-core/src/main/java/org/apache/tika/parser/RecursiveParserWrapper.java
+++ b/tika-core/src/main/java/org/apache/tika/parser/RecursiveParserWrapper.java
@@ -24,6 +24,7 @@ import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
+import org.apache.tika.config.OutputLimits;
 import org.apache.tika.exception.CorruptedFileException;
 import org.apache.tika.exception.EncryptedDocumentException;
 import org.apache.tika.exception.TikaException;
@@ -162,9 +163,10 @@ public class RecursiveParserWrapper extends 
ParserDecorator {
                 throwOnWriteLimitReached = 
((WriteLimiter)factory).isThrowOnWriteLimitReached();
             }
         }
+        SecureHandlerCounter handlerCounter = new 
SecureHandlerCounter(writeLimit, tis);
         try {
             RecursivelySecureContentHandler secureContentHandler =
-                    new RecursivelySecureContentHandler(localHandler, tis, new 
SecureHandlerCounter(writeLimit),
+                    new RecursivelySecureContentHandler(localHandler, tis, 
handlerCounter,
                             throwOnWriteLimitReached, context);
             context.set(RecursivelySecureContentHandler.class, 
secureContentHandler);
             getWrappedParser().parse(tis, secureContentHandler, metadata, 
context);
@@ -177,6 +179,9 @@ public class RecursiveParserWrapper extends ParserDecorator 
{
             } else {
                 metadata.add(TikaCoreProperties.CONTAINER_EXCEPTION,
                         ExceptionUtils.format(e, context));
+                if (handlerCounter.zipBombDetected) {
+                    throw new TikaException("Zip bomb detected!", e);
+                }
                 throw e;
             }
         } finally {
@@ -281,6 +286,8 @@ public class RecursiveParserWrapper extends ParserDecorator 
{
                 if (WriteLimitReachedException.isWriteLimitReached(e)) {
                     metadata.add(TikaCoreProperties.WRITE_LIMIT_REACHED, 
"true");
                     throw e;
+                } else if (preParseHandler.handlerCounter.zipBombDetected) {
+                    throw e;
                 } else {
                     if (catchEmbeddedExceptions) {
                         ParserUtils.recordParserFailure(this, e, metadata, 
context);
@@ -334,9 +341,15 @@ public class RecursiveParserWrapper extends 
ParserDecorator {
         private boolean writeLimitReached = false;
         //total chars written to all handlers
         private int totalChars = 0;
+        //the container's stream: the denominator for the compression ratio 
across the tree
+        private final TikaInputStream rootStream;
+        //total chars produced by all handlers, whether or not written
+        private long ratioChars = 0;
+        private boolean zipBombDetected = false;
 
-        private SecureHandlerCounter(int totalWriteLimit) {
+        private SecureHandlerCounter(int totalWriteLimit, TikaInputStream 
rootStream) {
             this.totalWriteLimit = totalWriteLimit;
+            this.rootStream = rootStream;
         }
         /**
          * Given the requested length, how many characters are actually 
available
@@ -372,6 +385,26 @@ public class RecursiveParserWrapper extends 
ParserDecorator {
             this.handlerCounter = handlerCounter;
             this.throwOnWriteLimitReached = throwOnWriteLimitReached;
             this.parseContext = parseContext;
+            OutputLimits limits = OutputLimits.get(parseContext);
+            setOutputThreshold(limits.getZipBombThreshold());
+            setMaximumCompressionRatio(limits.getZipBombRatio());
+        }
+
+        /**
+         * Each embedded document's stream is decompressed, so the per-entry 
ratio
+         * can't see archive compression. Also check the whole tree's output
+         * against the container's bytes, as the concatenated path does.
+         */
+        @Override
+        protected void advance(int length) throws SAXException {
+            super.advance(length);
+            handlerCounter.ratioChars += length;
+            try {
+                checkCompressionRatio(handlerCounter.ratioChars, 
handlerCounter.rootStream);
+            } catch (SAXException e) {
+                handlerCounter.zipBombDetected = true;
+                throw e;
+            }
         }
 
         /**
diff --git 
a/tika-core/src/main/java/org/apache/tika/sax/SecureContentHandler.java 
b/tika-core/src/main/java/org/apache/tika/sax/SecureContentHandler.java
index d871342774..c0189868c6 100644
--- a/tika-core/src/main/java/org/apache/tika/sax/SecureContentHandler.java
+++ b/tika-core/src/main/java/org/apache/tika/sax/SecureContentHandler.java
@@ -76,7 +76,7 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
     /**
      * Maximum package entry nesting level.
      */
-    private int maxPackageEntryDepth = 10;
+    private int maxPackageEntryDepth = 20;
 
     /**
      * Decorates the given content handler with zip bomb prevention based
@@ -103,6 +103,7 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
      * @param context the ParseContext (may be null)
      * @return a configured SecureContentHandler
      */
+    @SuppressWarnings("removal")
     public static SecureContentHandler newInstance(ContentHandler handler, 
TikaInputStream stream,
                                                     ParseContext context) {
         SecureContentHandler sch = new SecureContentHandler(handler, stream);
@@ -181,7 +182,10 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
      * Returns the maximum package entry nesting level.
      *
      * @return maximum package entry nesting level
+     * @deprecated use {@link 
org.apache.tika.config.EmbeddedLimits#getMaxDepth()}.
+     *     To be removed in 4.3.
      */
+    @Deprecated(since = "4.2", forRemoval = true)
     public int getMaximumPackageEntryDepth() {
         return maxPackageEntryDepth;
     }
@@ -191,7 +195,10 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
      * exceeded then an exception gets thrown.
      *
      * @param depth maximum package entry nesting level
+     * @deprecated use {@link 
org.apache.tika.config.EmbeddedLimits#setMaxDepth(int)}.
+     *     To be removed in 4.3.
      */
+    @Deprecated(since = "4.2", forRemoval = true)
     public void setMaximumPackageEntryDepth(int depth) {
         this.maxPackageEntryDepth = depth;
     }
@@ -210,7 +217,7 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
         }
     }
 
-    private long getByteCount() throws SAXException {
+    private static long getByteCount(TikaInputStream stream) throws 
SAXException {
         try {
             //a declared Content-Length is the file's claim; only a measured 
length
             //or the bytes actually read can serve as the ratio's denominator
@@ -234,8 +241,21 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
      */
     protected void advance(int length) throws SAXException {
         characterCount += length;
+        checkCompressionRatio(characterCount, stream);
+    }
+
+    /**
+     * Throws if {@code characterCount} exceeds the output threshold and the 
maximum
+     * compression ratio against the bytes of {@code source}.
+     *
+     * @param characterCount output characters to check
+     * @param source         input stream whose bytes produced them
+     * @throws SAXException if a zip bomb is detected
+     */
+    protected void checkCompressionRatio(long characterCount, TikaInputStream 
source)
+            throws SAXException {
         if (characterCount > threshold) {
-            long byteCount = getByteCount();
+            long byteCount = getByteCount(source);
             if (characterCount > byteCount * ratio) {
                 throw new SecureSAXException("Suspected zip bomb: " + 
byteCount + " input bytes produced " + characterCount + " output characters");
             }
@@ -253,7 +273,7 @@ public class SecureContentHandler extends 
ContentHandlerDecorator {
 
         if ("div".equals(name) && 
"package-entry".equals(atts.getValue("class"))) {
             packageEntryDepths.addLast(currentDepth);
-            if (packageEntryDepths.size() >= maxPackageEntryDepth) {
+            if (packageEntryDepths.size() > maxPackageEntryDepth) {
                 throw new SecureSAXException("Suspected zip bomb: " + 
packageEntryDepths.size() +
                         " levels of package entry nesting");
             }
diff --git 
a/tika-core/src/test/java/org/apache/tika/sax/SecureContentHandlerTest.java 
b/tika-core/src/test/java/org/apache/tika/sax/SecureContentHandlerTest.java
index 6a4f624515..32ac2c6e94 100644
--- a/tika-core/src/test/java/org/apache/tika/sax/SecureContentHandlerTest.java
+++ b/tika-core/src/test/java/org/apache/tika/sax/SecureContentHandlerTest.java
@@ -182,7 +182,7 @@ public class SecureContentHandlerTest {
     public void testNestedEntries() throws SAXException {
         AttributesImpl atts = new AttributesImpl();
         atts.addAttribute("", "class", "class", "CDATA", "package-entry");
-        for (int i = 1; i < handler.getMaximumPackageEntryDepth(); i++) {
+        for (int i = 1; i <= handler.getMaximumPackageEntryDepth(); i++) {
             handler.startElement("", "div", "div", atts);
         }
         try {
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/RecursiveParserWrapperTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/RecursiveParserWrapperTest.java
index fb4d30525d..33f1ba5a16 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/RecursiveParserWrapperTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/RecursiveParserWrapperTest.java
@@ -19,15 +19,19 @@ package org.apache.tika.parser;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.zip.GZIPOutputStream;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.input.ClosedInputStream;
@@ -479,6 +483,25 @@ public class RecursiveParserWrapperTest extends TikaTest {
 
     }
 
+    @Test
+    public void testCompressionRatioAcrossEmbedded() throws Exception {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (GZIPOutputStream gz = new GZIPOutputStream(bos)) {
+            byte[] line = ("a ".repeat(50) + 
"\n").getBytes(StandardCharsets.US_ASCII);
+            for (int i = 0; i < 20000; i++) {
+                gz.write(line);
+            }
+        }
+        RecursiveParserWrapper wrapper = new 
RecursiveParserWrapper(AUTO_DETECT_PARSER);
+        RecursiveParserWrapperHandler handler = new 
RecursiveParserWrapperHandler(
+                new 
BasicContentHandlerFactory(BasicContentHandlerFactory.HANDLER_TYPE.TEXT, -1));
+        try (TikaInputStream tis = TikaInputStream.get(bos.toByteArray())) {
+            TikaException e = assertThrows(TikaException.class,
+                    () -> wrapper.parse(tis, handler, new Metadata(), new 
ParseContext()));
+            assertTrue(e.getMessage().contains("Zip bomb"));
+        }
+    }
+
     private List<Metadata> getMetadata(Metadata metadata,
                                        ContentHandlerFactory 
contentHandlerFactory,
                                        boolean catchEmbeddedExceptions,
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/CompressorParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/CompressorParserTest.java
index d85753d12c..8fd0f56fb7 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/CompressorParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/CompressorParserTest.java
@@ -41,7 +41,6 @@ import org.xml.sax.helpers.DefaultHandler;
 
 import org.apache.tika.TikaTest;
 import org.apache.tika.detect.zip.CompressorConstants;
-import org.apache.tika.exception.TikaException;
 import org.apache.tika.io.TikaInputStream;
 import org.apache.tika.metadata.HttpHeaders;
 import org.apache.tika.metadata.Metadata;
@@ -109,9 +108,8 @@ public class CompressorParserTest extends TikaTest {
                 
CompressorParserTest.class.getResourceAsStream("/test-documents/quine.gz") != 
null);
 
         
//https://blog.matthewbarber.io/2019/07/22/how-to-make-compressed-file-quines
-        assertThrows(TikaException.class, () -> {
-            getXML("quine.gz");
-        });
+        assertEquals("true",
+                
getXML("quine.gz").metadata.get(TikaCoreProperties.EMBEDDED_DEPTH_LIMIT_REACHED));
     }
 
     @Test
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/ZipParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/ZipParserTest.java
index afae21a842..586d4bc182 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/ZipParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/ZipParserTest.java
@@ -18,7 +18,6 @@ package org.apache.tika.parser.pkg;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
@@ -35,7 +34,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
 import org.apache.tika.Tika;
-import org.apache.tika.exception.TikaException;
 import org.apache.tika.io.TikaInputStream;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.metadata.TikaCoreProperties;
@@ -157,13 +155,12 @@ public class ZipParserTest extends AbstractPkgTest {
     }
 
     @Test
-    public void testQuine() {
+    public void testQuine() throws Exception {
         //Anti-virus can surreptitiously remove this file
         assumeTrue(
                 
ZipParserTest.class.getResourceAsStream("/test-documents/droste.zip") != null);
-        assertThrows(TikaException.class, () -> {
-            getXML("droste.zip");
-        });
+        assertEquals("true",
+                
getXML("droste.zip").metadata.get(TikaCoreProperties.EMBEDDED_DEPTH_LIMIT_REACHED));
     }
 
     @Test
diff --git 
a/tika-serialization/src/test/java/org/apache/tika/config/AllLimitsTest.java 
b/tika-serialization/src/test/java/org/apache/tika/config/AllLimitsTest.java
index ff07312d4e..9aae93ddee 100644
--- a/tika-serialization/src/test/java/org/apache/tika/config/AllLimitsTest.java
+++ b/tika-serialization/src/test/java/org/apache/tika/config/AllLimitsTest.java
@@ -143,7 +143,7 @@ public class AllLimitsTest extends TikaTest {
         // Helper methods should return defaults when context is null
         EmbeddedLimits embeddedLimits = EmbeddedLimits.get(null);
         assertNotNull(embeddedLimits);
-        assertEquals(EmbeddedLimits.UNLIMITED, embeddedLimits.getMaxDepth());
+        assertEquals(EmbeddedLimits.DEFAULT_MAX_DEPTH, 
embeddedLimits.getMaxDepth());
 
         OutputLimits outputLimits = OutputLimits.get(null);
         assertNotNull(outputLimits);
diff --git 
a/tika-serialization/src/test/java/org/apache/tika/config/EmbeddedLimitsTest.java
 
b/tika-serialization/src/test/java/org/apache/tika/config/EmbeddedLimitsTest.java
index 4bb4873701..eaead953c2 100644
--- 
a/tika-serialization/src/test/java/org/apache/tika/config/EmbeddedLimitsTest.java
+++ 
b/tika-serialization/src/test/java/org/apache/tika/config/EmbeddedLimitsTest.java
@@ -58,7 +58,7 @@ public class EmbeddedLimitsTest extends TikaTest {
     @Test
     public void testDefaults() {
         EmbeddedLimits limits = new EmbeddedLimits();
-        assertEquals(EmbeddedLimits.UNLIMITED, limits.getMaxDepth());
+        assertEquals(EmbeddedLimits.DEFAULT_MAX_DEPTH, limits.getMaxDepth());
         assertFalse(limits.isThrowOnMaxDepth());
         assertEquals(EmbeddedLimits.UNLIMITED, limits.getMaxCount());
         assertFalse(limits.isThrowOnMaxCount());
@@ -69,13 +69,13 @@ public class EmbeddedLimitsTest extends TikaTest {
         // Test with null context
         EmbeddedLimits limits = EmbeddedLimits.get(null);
         assertNotNull(limits);
-        assertEquals(EmbeddedLimits.UNLIMITED, limits.getMaxDepth());
+        assertEquals(EmbeddedLimits.DEFAULT_MAX_DEPTH, limits.getMaxDepth());
 
         // Test with context that doesn't have EmbeddedLimits
         ParseContext context = new ParseContext();
         limits = EmbeddedLimits.get(context);
         assertNotNull(limits);
-        assertEquals(EmbeddedLimits.UNLIMITED, limits.getMaxDepth());
+        assertEquals(EmbeddedLimits.DEFAULT_MAX_DEPTH, limits.getMaxDepth());
 
         // Test with context that has EmbeddedLimits
         EmbeddedLimits customLimits = new EmbeddedLimits(10, true, 500, false);
diff --git 
a/tika-serialization/src/test/java/org/apache/tika/config/OutputLimitsTest.java 
b/tika-serialization/src/test/java/org/apache/tika/config/OutputLimitsTest.java
index 41e23cd570..7a663e97fc 100644
--- 
a/tika-serialization/src/test/java/org/apache/tika/config/OutputLimitsTest.java
+++ 
b/tika-serialization/src/test/java/org/apache/tika/config/OutputLimitsTest.java
@@ -65,7 +65,7 @@ public class OutputLimitsTest extends TikaTest {
         assertEquals(OutputLimits.UNLIMITED, limits.getWriteLimit());
         assertFalse(limits.isThrowOnWriteLimit());
         assertEquals(100, limits.getMaxXmlDepth());
-        assertEquals(10, limits.getMaxPackageEntryDepth());
+        assertEquals(20, limits.getMaxPackageEntryDepth());
         assertEquals(1_000_000, limits.getZipBombThreshold());
         assertEquals(100, limits.getZipBombRatio());
     }
diff --git 
a/tika-serialization/src/test/java/org/apache/tika/config/loader/TikaLoaderTest.java
 
b/tika-serialization/src/test/java/org/apache/tika/config/loader/TikaLoaderTest.java
index 2e137c87f0..5f14a6d714 100644
--- 
a/tika-serialization/src/test/java/org/apache/tika/config/loader/TikaLoaderTest.java
+++ 
b/tika-serialization/src/test/java/org/apache/tika/config/loader/TikaLoaderTest.java
@@ -372,7 +372,7 @@ public class TikaLoaderTest {
 
         // Create defaults - some values will be overridden by JSON, others 
kept
         EmbeddedLimits defaults = new EmbeddedLimits();
-        // Default values from EmbeddedLimits: maxDepth=UNLIMITED, 
maxCount=UNLIMITED, throwOnMax*=false
+        // Default values from EmbeddedLimits: maxDepth=DEFAULT_MAX_DEPTH, 
maxCount=UNLIMITED, throwOnMax*=false
 
         // Load with defaults - JSON has: maxDepth=5, throwOnMaxDepth=true, 
maxCount=100, throwOnMaxCount=false
         EmbeddedLimits config = loader.loadConfig(EmbeddedLimits.class, 
defaults);
@@ -384,7 +384,7 @@ public class TikaLoaderTest {
         assertFalse(config.isThrowOnMaxCount(), "throwOnMaxCount should be 
from JSON");
 
         // Verify original defaults object was NOT modified
-        assertEquals(EmbeddedLimits.UNLIMITED, defaults.getMaxDepth(), 
"Original defaults should be unchanged");
+        assertEquals(EmbeddedLimits.DEFAULT_MAX_DEPTH, defaults.getMaxDepth(), 
"Original defaults should be unchanged");
     }
 
     @Test

Reply via email to