Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package com.mirth.connect.util.messagewriter;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

Expand Down Expand Up @@ -41,6 +42,17 @@ private MessageWriterFactory() {}
public MessageWriter getMessageWriter(MessageWriterOptions options, Encryptor encryptor) throws MessageWriterException {
String baseFolder = StringUtils.defaultString(options.getBaseFolder(), System.getProperty("user.dir"));
String rootFolder = FilenameUtils.getAbsolutePath(new File(baseFolder), options.getRootFolder());
// Path traversal validation: Ensure that rootFolder is a subdirectory of baseFolder
try {
File baseDir = new File(baseFolder).getCanonicalFile();
File rootDir = new File(rootFolder).getCanonicalFile();
if (!isSafeSubdirectory(baseDir, rootDir)) {
throw new MessageWriterException("Invalid root folder: traversal outside of base directory is not allowed.");
}
} catch (java.io.IOException e) {
throw new MessageWriterException("Failed to validate export folder path: " + e.getMessage(), e);
}

String filePattern = options.getFilePattern();

if (filePattern.substring(0, 1).equals(IOUtils.DIR_SEPARATOR)) {
Expand Down Expand Up @@ -86,4 +98,22 @@ private String getArchiveExtension(String archiver, String compressor) {

return archiver + "." + compressor;
}
/**
* Checks if candidate is a subdirectory (or the same directory) as base.
*/
private boolean isSafeSubdirectory(File base, File candidate) {
try {
String basePath = base.getCanonicalPath();
String candidatePath = candidate.getCanonicalPath();
if (basePath.equals(candidatePath)) {
return true;
}
if (candidatePath.startsWith(basePath + File.separator)) {
return true;
}
return false;
} catch (java.io.IOException e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,18 @@ public String getFilePattern() {
/**
* @param filePattern
* A string defining the folder/filename(s) for writing messages. It may contain
* variables to be replaced.
* variables to be replaced only if allowed by internal logic. User-supplied input is sanitized.
*/
public void setFilePattern(String filePattern) {
this.filePattern = filePattern;
// Only allow safe patterns: alphanumerics, underscore, dash, dot, forward slash
// Disallow Velocity special chars: $, #, {, }
if (filePattern != null && filePattern.matches("^[a-zA-Z0-9_\\-/\\.]+$")) {
this.filePattern = filePattern;
} else {
throw new IllegalArgumentException(
"Invalid filePattern: Only alphanumerics, underscore, dash, dot, and slash are permitted. Velocity expressions are not allowed."
);
}
}

public String getArchiveFileName() {
Expand Down