Skip to content

Commit cb617a5

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

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

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

+37-27
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,26 @@ protected static void decompressTarBz2(Path source, Path target) throws IOExcept
154155
}
155156
}
156157

157-
private static void decompressTar(Path target, TarArchiveInputStream tarInputStream)
158-
throws IOException {
158+
public static void decompressTar(Path target, TarArchiveInputStream tarInputStream) throws IOException {
159159
TarArchiveEntry entry;
160160
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);
161+
Path resolvedPath = target.resolve(entry.getName()).normalize();
162+
File file = resolvedPath.toFile();
163+
164+
String canonicalDestinationPath = file.getCanonicalPath();
165+
String canonicalTargetPath = target.toFile().getCanonicalPath();
166+
167+
if (canonicalDestinationPath.startsWith(canonicalTargetPath)) {
168+
if (entry.isDirectory()) {
169+
Files.createDirectories(resolvedPath);
170+
} else {
171+
Files.createDirectories(resolvedPath.getParent());
172+
try (BufferedOutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(resolvedPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
173+
tarInputStream.transferTo(outputStream);
174+
}
172175
}
176+
} else {
177+
throw new IOException("Entry is outside of the target directory");
173178
}
174179
}
175180
}
@@ -183,23 +188,28 @@ private static void decompressTar(Path target, TarArchiveInputStream tarInputStr
183188
*/
184189
@SuppressWarnings("squid:S5042")
185190
protected static void decompressZip(Path source, Path target) throws IOException {
186-
Files.createDirectories(target);
187-
try (var zipFile = new ZipFile(source.toFile())) {
191+
try (ZipFile zipFile = new ZipFile(source.toFile())) {
188192
var entries = zipFile.entries();
189193
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);
194+
ZipEntry entry = entries.nextElement();
195+
Path resolvedPath = target.resolve(entry.getName()).normalize();
196+
File file = resolvedPath.toFile();
197+
198+
String canonicalDestinationPath = file.getCanonicalPath();
199+
String canonicalTargetPath = target.toFile().getCanonicalPath();
200+
201+
if (canonicalDestinationPath.startsWith(canonicalTargetPath)) {
202+
if (entry.isDirectory()) {
203+
Files.createDirectories(resolvedPath);
204+
} else {
205+
Files.createDirectories(resolvedPath.getParent());
206+
try (BufferedInputStream input = new BufferedInputStream(zipFile.getInputStream(entry));
207+
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file))) {
208+
input.transferTo(output);
209+
}
202210
}
211+
} else {
212+
throw new IOException("Entry is outside of the target directory");
203213
}
204214
}
205215
}

0 commit comments

Comments
 (0)