HMCL-dev/HMCL · error · IOException
Malformed modpack configuration
Error message
Malformed modpack configuration
What it means
Security check during Modrinth pack completion: each file's declared path is resolved against the instance run directory and normalized; if the result escapes the run directory, an IOException 'Unsecure path' is thrown. This blocks path-traversal attacks via malicious file entries in a modpack index.
Solutions
- Inspect the pack's modrinth.index.json for ../ or absolute paths in files[].path and remove/correct them
- Re-download the pack from the official Modrinth page
- Only import packs from trusted authors/sources
Example fix
// before (index entry escapes instance)
{"path": "../../.minecraft/steal.txt", ...}
// after
{"path": "mods/legit-mod.jar", ...} Defensive patterns
Strategy: validation
Validate before calling
Path p = runDirectory.resolve(entry.getPath()).toAbsolutePath().normalize();
if (!p.startsWith(runDirectory))
throw new IllegalArgumentException("Unsafe path in pack: " + entry.getPath()); Type guard
boolean safe = runDirectory.resolve(p).toAbsolutePath().normalize().startsWith(runDirectory);
Try / catch
try { completionTask.execute(); } catch (IOException e) { if (e.getMessage().startsWith("Unsecure path")) { /* reject pack as malicious/corrupt */ } else throw e; } Prevention
- Only import packs from trusted Modrinth authors
- Scan index files[] paths for ../ before installing
- Keep HMCL updated for current traversal checks
When it happens
Trigger: Importing/completing a Modrinth pack whose modrinth.index.json files[] entries contain paths like '../something' or absolute paths resolving outside the run directory.
Common situations: Downloading a maliciously crafted modpack that tries to overwrite files outside the instance; a corrupted index with malformed relative paths; symbolic-link/normalization edge cases.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Theme-pack asset entry contains an unsafe segment:
- Theme-pack asset escapes the installed directory:
- Theme-pack entry contains an unsafe segment
- path escapes instance root
- Unsecure path:
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/e2eda203ccbe80f6.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java:156
if (isMinecraftDirectory(secondLayer)) {
return firstLayer.getName() + "/" + secondLayer.getName();
}
}
}
}
throw new UnsupportedModpackException(modpackName);
}
private static boolean isMinecraftDirectory(ArchiveFileTree.Dir<?> dir) {
return dir.getSubDirs().containsKey("versions") && (dir.isRoot() || ".minecraft".equals(dir.getName()));
}
public static ModpackConfiguration<?> readModpackConfiguration(Path file) throws IOException {
try {
return JsonUtils.fromJsonFile(file, ModpackConfiguration.class);
} catch (JsonParseException e) {
throw new IOException("Malformed modpack configuration");
}
}
public static Task<?> getInstallTask(HMCLGameRepository repository, ServerModpackManifest manifest, GameInstanceID instanceId, Modpack modpack) {
ExceptionalRunnable<?> success = () -> {
repository.refresh();
repository.getInstance(instanceId).enableIsolation();
};
ExceptionalConsumer<Exception, ?> failure = ex -> {
if (ex instanceof ModpackCompletionException && !(ex.getCause() instanceof FileNotFoundException)) {
success.run();
// This is tolerable and we will not delete the game
}
};
return new ServerModpackRemoteInstallTask(repository.getDependency(), manifest, instanceId)
.whenComplete(Schedulers.defaultScheduler(), success, failure)View on GitHub (pinned to 24702dc5a0)