HMCL-dev/HMCL · error · IllegalArgumentException

Theme-pack asset entry contains an unsafe segment:

Error message

Theme-pack asset entry contains an unsafe segment: 

What it means

Each '/'-separated segment of an asset entry name must be non-empty and must not be '.' or '..'. Violations throw IllegalArgumentException("Theme-pack asset entry contains an unsafe segment: <name>"). This blocks path traversal and malformed names inside the pack.

Solutions

  1. Remove '.', '..' and duplicate slashes from the entry name (normalize before calling)
  2. Reject or sanitize pack entries containing traversal segments before lookup
  3. Canonicalize the intended path and verify it stays under assets/

Example fix

// before
ThemePackAsset.of("assets/" + userInput + ".png"); // userInput = "../x"
// after
String safe = userInput.replace("\\", "/");
if (safe.contains("..") || safe.contains("//")) throw new IllegalArgumentException("bad name");
ThemePackAsset.of("assets/" + safe + ".png");
Defensive patterns

Strategy: validation

Validate before calling

static boolean hasSafeSegments(String name) {
    String n = name.replace('\\', '/');
    for (String seg : n.split("/")) {
        if (seg.isEmpty() || seg.equals(".") || seg.equals("..")) return false;
    }
    return true;
}

Type guard

static boolean isSafeSegment(String seg) {
    return !seg.isEmpty() && !".".equals(seg) && !"..".equals(seg);
}

Try / catch

try {
    ThemePackAsset.of(entryName);
} catch (IllegalArgumentException e) {
    log.warn("Rejected unsafe asset entry: " + e.getMessage());
}

Prevention

When it happens

Trigger: Passing names like "assets/../secrets.png", "assets//icon.png" (empty segment), or "assets/./x.png" to ThemePackAsset / normalizeEntryName.

Common situations: Malicious or buggy pack manifests containing ../ traversal attempts; string concatenation producing double slashes or redundant dots.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/6f9a223f6bfb3611. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackAsset.java:76

        Objects.requireNonNull(entryName);

        String normalized = entryName.trim().replace('\\', '/');
        if (normalized.isEmpty()) {
            throw new IllegalArgumentException("Theme-pack asset entry is empty");
        }
        if (normalized.startsWith("/") || normalized.matches("^[A-Za-z]:.*")) {
            throw new IllegalArgumentException("Theme-pack asset entry must be relative: " + entryName);
        }
        if (!normalized.startsWith(ASSETS_PREFIX)) {
            throw new IllegalArgumentException("Theme-pack asset entry must be under assets/: " + entryName);
        }
        if (normalized.endsWith("/")) {
            throw new IllegalArgumentException("Theme-pack asset entry must be a file: " + entryName);
        }

        for (String segment : normalized.split("/")) {
            if (segment.isEmpty() || ".".equals(segment) || "..".equals(segment)) {
                throw new IllegalArgumentException("Theme-pack asset entry contains an unsafe segment: " + entryName);
            }
            for (int i = 0; i < segment.length(); i++) {
                char ch = segment.charAt(i);
                if (Character.isISOControl(ch) || ch == '\0') {
                    throw new IllegalArgumentException("Theme-pack asset entry contains a control character: " + entryName);
                }
            }
        }
        return normalized;
    }
}

View on GitHub (pinned to 24702dc5a0)