You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "govind-gupta-tfs (via GitHub)" <gi...@apache.org> on 2025/10/08 10:07:25 UTC
Re: [PR] Amend description of FilenameUtils#getFullPathNoEndSeparator(String) to reflect correct named user result with trailing slash [commons-io]
govind-gupta-tfs commented on PR #553:
URL: https://github.com/apache/commons-io/pull/553#issuecomment-3380782150
`package com.thermofisher.gsd.archive;
import org.apache.commons.lang3.Validate;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Set;
public class PathValidator {
private static final Set<String> RESERVED_NAMES = Set.of(
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
"COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
"LPT7", "LPT8", "LPT9"
);
public static void validateSafePathComponent(String component) {
// --- 1. Basic Checks (Using Apache Commons Lang) ---
Validate.notBlank(component, "Path component must not be blank");
Validate.isTrue(component.length() <= 255, "Path component too long");
// Pre-decode raw dangerous percent encodings
String lower = component.toLowerCase(Locale.ROOT);
if (lower.contains("%2f") || lower.contains("%5c") || lower.contains("%00")) {
throw new IllegalArgumentException("Encoded separator/null not allowed: " + component);
}
// --- 2. Decoding ---
String decoded;
try {
decoded = URLDecoder.decode(component, StandardCharsets.UTF_8);
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Invalid percent encoding: " + component);
}
// --- 3. Path Traversal/Normalization Check (Using Path API) ---
Path p;
try {
p = Path.of(decoded);
} catch (InvalidPathException e) {
throw new IllegalArgumentException("Invalid path syntax: " + component);
}
// Critical Path Traversal check: must be a single name and not contain '..' or '.'
if (p.isAbsolute() || p.getNameCount() != 1 || !p.normalize().equals(p)) {
throw new IllegalArgumentException("Traversal/dot segments or absolute path not allowed: " + component);
}
String name = p.getFileName().toString();
// --- 4. Final Name/Custom Policy Checks ---
// Basic character / separator checks
if (name.contains("/") || name.contains("\\") || name.indexOf('\0') >= 0 || name.contains("+")) {
throw new IllegalArgumentException("Unsafe characters (separators/null/plus): " + component);
}
// Control chars
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (c < 0x20 || c == 0x7F) {
throw new IllegalArgumentException("Control character present: " + component);
}
}
// Dot-only or reserved dot forms & Trailing space/dot
if (name.equals(".") || name.equals("..") || name.matches("\\.{2,}") ||
name.endsWith(" ") || name.endsWith(".")) {
throw new IllegalArgumentException("Invalid dot sequence or trailing space/dot: " + component);
}
// Allowlist
if (!name.matches("[A-Za-z0-9._-]+")) {
throw new IllegalArgumentException("Disallowed characters: " + component);
}
// Windows reserved device names
if (RESERVED_NAMES.contains(name.toUpperCase(Locale.ROOT))) {
throw new IllegalArgumentException("Reserved device name: " + component);
}
}
}`
@garydgregory can we use the above code to avoid path injection in user provided paths in windows machine.
It can further be optimized for other OS
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@commons.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org