Skip to content

Commit 0f29daf

Browse files
committed
Prevent zip slip and path injection (#875)
1 parent 375d0a3 commit 0f29daf

File tree

1 file changed

+38
-26
lines changed

1 file changed

+38
-26
lines changed

baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/DecompressFile.java

+38-26
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.nio.file.StandardOpenOption;
2525
import java.util.StringJoiner;
2626
import java.util.zip.GZIPInputStream;
27+
import java.util.zip.ZipEntry;
2728
import java.util.zip.ZipFile;
2829
import org.apache.baremaps.workflow.Task;
2930
import org.apache.baremaps.workflow.WorkflowContext;
@@ -154,22 +155,27 @@ protected static void decompressTarBz2(Path source, Path target) throws IOExcept
154155
}
155156
}
156157

157-
private static void decompressTar(Path target, TarArchiveInputStream tarInputStream)
158+
public static void decompressTar(Path target, TarArchiveInputStream tarInputStream)
158159
throws IOException {
159160
TarArchiveEntry entry;
160161
while ((entry = tarInputStream.getNextEntry()) != null) {
161-
var path = target.resolve(entry.getName());
162-
if (entry.isDirectory()) {
163-
Files.createDirectories(path);
164-
} else {
165-
Files.createDirectories(path.getParent());
166-
Files.write(path, new byte[] {},
167-
StandardOpenOption.CREATE,
168-
StandardOpenOption.TRUNCATE_EXISTING);
169-
try (BufferedOutputStream outputStream =
170-
new BufferedOutputStream(Files.newOutputStream(path))) {
171-
tarInputStream.transferTo(outputStream);
162+
File destination = target.resolve(entry.getName()).normalize().toFile();
163+
String canonicalDestinationPath = destination.getCanonicalPath();
164+
String canonicalTargetPath = target.toFile().getCanonicalPath();
165+
if (canonicalDestinationPath.startsWith(canonicalTargetPath)) {
166+
if (entry.isDirectory()) {
167+
Files.createDirectories(destination.toPath());
168+
} else {
169+
Files.createDirectories(destination.toPath().getParent());
170+
try (BufferedOutputStream outputStream =
171+
new BufferedOutputStream(Files.newOutputStream(destination.toPath(),
172+
StandardOpenOption.CREATE,
173+
StandardOpenOption.TRUNCATE_EXISTING))) {
174+
tarInputStream.transferTo(outputStream);
175+
}
172176
}
177+
} else {
178+
throw new IOException("Entry is outside of the target directory");
173179
}
174180
}
175181
}
@@ -183,23 +189,29 @@ private static void decompressTar(Path target, TarArchiveInputStream tarInputStr
183189
*/
184190
@SuppressWarnings("squid:S5042")
185191
protected static void decompressZip(Path source, Path target) throws IOException {
186-
Files.createDirectories(target);
187-
try (var zipFile = new ZipFile(source.toFile())) {
192+
try (ZipFile zipFile = new ZipFile(source.toFile())) {
188193
var entries = zipFile.entries();
189194
while (entries.hasMoreElements()) {
190-
var entry = entries.nextElement();
191-
var path = target.resolve(entry.getName());
192-
if (entry.isDirectory()) {
193-
Files.createDirectories(path);
194-
} else {
195-
Files.createDirectories(path.getParent());
196-
Files.write(path, new byte[] {},
197-
StandardOpenOption.CREATE,
198-
StandardOpenOption.TRUNCATE_EXISTING);
199-
try (var input = new BufferedInputStream(zipFile.getInputStream(entry));
200-
var output = new BufferedOutputStream(new FileOutputStream(path.toFile()))) {
201-
input.transferTo(output);
195+
ZipEntry entry = entries.nextElement();
196+
File destination = target.resolve(entry.getName()).normalize().toFile();
197+
String canonicalDestinationPath = destination.getCanonicalPath();
198+
String canonicalTargetPath = target.toFile().getCanonicalPath();
199+
200+
if (canonicalDestinationPath.startsWith(canonicalTargetPath)) {
201+
if (entry.isDirectory()) {
202+
Files.createDirectories(destination.toPath());
203+
} else {
204+
Files.createDirectories(destination.toPath().getParent());
205+
try (BufferedInputStream input = new BufferedInputStream(zipFile.getInputStream(entry));
206+
BufferedOutputStream output =
207+
new BufferedOutputStream(Files.newOutputStream(destination.toPath(),
208+
StandardOpenOption.CREATE,
209+
StandardOpenOption.TRUNCATE_EXISTING))) {
210+
input.transferTo(output);
211+
}
202212
}
213+
} else {
214+
throw new IOException("Entry is outside of the target directory");
203215
}
204216
}
205217
}

0 commit comments

Comments
 (0)