{"record":{"id":"e8500e707091e374","repo":"HMCL-dev/HMCL","slug":"theme-pack-entry-contains-a-control-character-e","errorCode":null,"errorMessage":"Theme-pack entry contains a control character: ${entryName}","messagePattern":"Theme-pack entry contains a control character: (.+?)","errorType":"validation","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java","lineNumber":1416,"sourceCode":"        String normalized = entryName.trim().replace('\\\\', '/');\n        if (normalized.endsWith(\"/\")) {\n            normalized = normalized.substring(0, normalized.length() - 1);\n        }\n        if (normalized.isEmpty()) {\n            throw new IOException(\"Theme-pack entry is empty\");\n        }\n        if (normalized.startsWith(\"/\") || normalized.matches(\"^[A-Za-z]:.*\")) {\n            throw new IOException(\"Theme-pack entry must be relative: \" + entryName);\n        }\n\n        for (String segment : normalized.split(\"/\")) {\n            if (segment.isEmpty() || \".\".equals(segment) || \"..\".equals(segment)) {\n                throw new IOException(\"Theme-pack entry contains an unsafe segment: \" + entryName);\n            }\n            for (int i = 0; i < segment.length(); i++) {\n                char ch = segment.charAt(i);\n                if (Character.isISOControl(ch) || ch == '\\0') {\n                    throw new IOException(\"Theme-pack entry contains a control character: \" + entryName);\n                }\n            }\n        }\n        return normalized;\n    }\n\n    /// Checks that a theme-pack zip entry belongs to the current file layout.\n    private static void checkSupportedThemePackEntry(String entryName) throws IOException {\n        if (!ThemePackExporter.MANIFEST_ENTRY.equals(entryName)\n                && !\"assets\".equals(entryName)\n                && !entryName.startsWith(\"assets/\")) {\n            throw new IOException(\"Unsupported theme-pack entry: \" + entryName);\n        }\n    }\n\n    /// Deletes an existing file, symbolic link, or directory tree.\n    private static void deleteIfExists(Path path) throws IOException {\n        if (Files.exists(path) || Files.isSymbolicLink(path)) {","sourceCodeStart":1398,"sourceCodeEnd":1434,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java#L1398-L1434","documentation":"ThemePackManager scans every character of each entry-name segment and rejects names containing ISO control characters or NUL bytes. Control characters are invalid in filesystem path components and can be used to obfuscate malicious paths, so such archives are refused.","triggerScenarios":"Installing a zip whose entry names contain characters like \\u0000, \\n, \\t, or other control codes — typically from binary-corrupted archives or hostile packs.","commonSituations":"Zips whose central directory was corrupted or hand-edited; archives generated by non-Java tools embedding raw bytes in names; deliberately malicious packs.","solutions":["Repack the archive ensuring entry names use only printable, filesystem-safe characters.","Regenerate the pack with ThemePackExporter instead of editing an existing zip.","Treat the source archive as untrusted/corrupted; do not attempt to strip control characters to bypass the check."],"exampleFix":"// before\nzip.putNextEntry(new ZipArchiveEntry(\"assets/bg\\u0000.png\"));\n// after\nString safe = name.chars().filter(c -> !Character.isISOControl(c)).collect(...); // better: validate & reject before writing","handlingStrategy":"validation","validationCode":"for (var e : Collections.list(new ZipFile(pack).entries())) {\n    if (e.getName().chars().anyMatch(Character::isISOControl)) throw new IllegalArgumentException(\"control char in entry: \" + e.getName());\n}","typeGuard":null,"tryCatchPattern":"try {\n    ThemePackManager.install(pack, dir);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"control character\")) {\n      ui.show(\"Theme pack rejected: entry names contain invalid characters.\");\n    } else throw e;\n}","preventionTips":["Validate entry names against a printable-character whitelist when creating packs.","Reject rather than sanitize hostile archives.","Avoid hand-editing zip structures with binary tools."],"tags":["zip","security","validation"],"backgroundTag":"path-traversal-blocked","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}