Skip to content

Commit 4dcae88

Browse files
committed
Avoid infinite ZIP size handling
1 parent 1622315 commit 4dcae88

2 files changed

Lines changed: 42 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ With 64bit Java, the default stack size of the Oracle JVM is already 1MB.
139139
v12.0.3 - work in progress
140140
* Added new class `ValidationExecutorSchematronBuilder` as a fluent builder for `ValidationExecutorSchematron`
141141
* Fixed SVRL generation for partial validation sources (child nodes) in XSLT-based Schematron validation. When validating a node extracted from an envelope (e.g. SBDH unwrap) via `ValidationSourceXML.createPartial`, the XSLT transformation now receives a proper Document node.
142+
* Added ZIP bomb protection in `DefaultVESLoaderXSD` with a configurable maximum unzipped size (default 50 MB) via `setMaxUnzippedSize`/`getMaxUnzippedSize`
142143

143144
v12.0.2 - 2026-04-02
144145
* Added new method `ValidationResultList.addAt`

phive-ves-engine/src/main/java/com/helger/phive/ves/engine/load/DefaultVESLoaderXSD.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.math.RoundingMode;
2121
import java.net.URI;
2222
import java.util.Locale;
23+
import java.util.concurrent.atomic.AtomicLong;
2324
import java.util.zip.ZipEntry;
2425
import java.util.zip.ZipInputStream;
2526

@@ -32,6 +33,7 @@
3233
import org.w3c.dom.ls.LSResourceResolver;
3334

3435
import com.helger.annotation.Nonempty;
36+
import com.helger.annotation.Nonnegative;
3537
import com.helger.base.enforce.ValueEnforcer;
3638
import com.helger.base.io.nonblocking.NonBlockingByteArrayOutputStream;
3739
import com.helger.base.numeric.BigHelper;
@@ -77,13 +79,39 @@ public class DefaultVESLoaderXSD implements IVESLoaderXSD
7779
public static final String RESOURCE_TYPE_XSD = "xsd";
7880
public static final String FILE_EXT_XSD = '.' + RESOURCE_TYPE_XSD;
7981

82+
/** Default maximum unzipped size: 50 MB */
83+
public static final long DEFAULT_MAX_UNZIPPED_SIZE = 50L * 1024 * 1024;
84+
85+
private static final AtomicLong MAX_UNZIPPED_SIZE = new AtomicLong (DEFAULT_MAX_UNZIPPED_SIZE);
8086
private static final Logger LOGGER = LoggerFactory.getLogger (DefaultVESLoaderXSD.class);
8187

88+
/**
89+
* @return The maximum allowed unzipped size in bytes. Defaults to
90+
* {@link #DEFAULT_MAX_UNZIPPED_SIZE}.
91+
*/
92+
@Nonnegative
93+
public static long getMaxUnzippedSize ()
94+
{
95+
return MAX_UNZIPPED_SIZE.get ();
96+
}
97+
98+
/**
99+
* Set the maximum allowed unzipped size in bytes. This is a safeguard against ZIP bomb attacks.
100+
*
101+
* @param nMaxUnzippedSize
102+
* The maximum unzipped size in bytes. Must be > 0.
103+
*/
104+
public static void setMaxUnzippedSize (@Nonnegative final long nMaxUnzippedSize)
105+
{
106+
ValueEnforcer.isGT0 (nMaxUnzippedSize, "MaxUnzippedSize");
107+
MAX_UNZIPPED_SIZE.set (nMaxUnzippedSize);
108+
}
109+
82110
@Nullable
83-
private static final String _unifyPath (@Nullable final String x)
111+
private static final String _unifyPath (@Nullable final String sPath)
84112
{
85113
// Convert any "\" to "/"
86-
String ret = FilenameHelper.getPathUsingUnixSeparator (x);
114+
String ret = FilenameHelper.getPathUsingUnixSeparator (sPath);
87115
if (ret != null)
88116
{
89117
// Make absolute to simply LS resource resolving
@@ -225,13 +253,23 @@ public IValidationExecutor <IValidationSourceXML> loadXSD (@NonNull final IRepoS
225253
bFoundMain = true;
226254

227255
// Read ZIP entry
256+
final long nMaxLen = getMaxUnzippedSize ();
228257
try (final NonBlockingByteArrayOutputStream aBAOS = new NonBlockingByteArrayOutputStream ())
229258
{
230259
int nLen;
231260
while ((nLen = aZIS.read (aBuffer)) > 0)
232261
{
233-
aBAOS.write (aBuffer, 0, nLen);
234262
nUnzippedLen += nLen;
263+
if (nUnzippedLen > nMaxLen)
264+
{
265+
aErrorList.add (SingleError.builderError ()
266+
.errorText ("XSD ZIP file exceeds maximum unzipped size of " +
267+
SizeHelper.getSizeHelperOfLocale (Locale.ROOT)
268+
.getAsMatching (nMaxLen))
269+
.build ());
270+
return null;
271+
}
272+
aBAOS.write (aBuffer, 0, nLen);
235273
}
236274

237275
// Remember ZIP entry in map

0 commit comments

Comments
 (0)