{"record":{"id":"2feb3d88bda7211c","repo":"theonedev/onedev","slug":"invalid-new-path-path","errorCode":null,"errorMessage":"Invalid new path: <path>","messagePattern":"Invalid new path: <path>","errorType":"validation","errorClass":"BlobEditException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/git/BlobEdits.java","lineNumber":51,"sourceCode":"\t\tthis(new HashSet<>(), new HashMap<>());\n\t}\n\t\n\tpublic BlobEdits(Set<String> oldPaths, Map<String, BlobContent> newBlobs) {\n\t\tthis.oldPaths = new HashSet<>();\n\t\tfor (String oldPath: oldPaths) {\n\t\t\tString normalizedPath = GitUtils.normalizePath(oldPath);\n\t\t\tif (normalizedPath != null)\n\t\t\t\tthis.oldPaths.add(normalizedPath);\n\t\t\telse\n\t\t\t\tthrow new BlobEditException(\"Invalid old path: \" + oldPath);\n\t\t}\n\t\tthis.newBlobs = new HashMap<>();\n\t\tfor (Map.Entry<String, BlobContent> entry: newBlobs.entrySet()) { \n\t\t\tString normalizedPath = GitUtils.normalizePath(entry.getKey());\n\t\t\tif (normalizedPath != null)\n\t\t\t\tthis.newBlobs.put(normalizedPath, entry.getValue());\n\t\t\telse\n\t\t\t\tthrow new BlobEditException(\"Invalid new path: \" + entry.getKey());\n\t\t}\n\t}\n\n\tpublic Set<String> getOldPaths() {\n\t\treturn oldPaths;\n\t}\n\n\tpublic Map<String, BlobContent> getNewBlobs() {\n\t\treturn newBlobs;\n\t}\n\n\tpublic void applySuggestion(Project project, Mark mark, List<String> suggestion, ObjectId commitId) {\n\t\tMap<String, BlobContent> newBlobs = getNewBlobs();\n\t\tBlobContent blobContent = newBlobs.get(mark.getPath());\n\t\tif (blobContent == null) {\n\t\t\tBlobIdent newBlobIdent = new BlobIdent(commitId.name(), mark.getPath());\n\t\t\tBlob newBlob = project.getBlob(newBlobIdent, false);\n\t\t\tif (newBlob == null || newBlob.getText() == null || newBlob.getLfsPointer() != null)","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/git/BlobEdits.java#L33-L69","documentation":"The BlobEdits constructor normalizes each key of the newBlobs map via GitUtils.normalizePath. Keys that are empty, absolute, or contain '..' segments normalize to null and cause a BlobEditException(\"Invalid new path: ...\"). This validates the destination paths of created/modified files before any git operation is attempted.","triggerScenarios":"new BlobEdits(oldPaths, newBlobs) where a newBlobs map key is an invalid path (empty string, starts with '/', contains '..', or otherwise fails GitUtils.normalizePath).","commonSituations":"API clients committing files with absolute paths like \"/README.md\"; crafted requests attempting path traversal; UI forms submitting empty file names for new files; programmatic commits building paths by naive string concatenation.","solutions":["Use normalized relative paths as newBlobs keys (e.g. \"docs/file.md\", never \"/docs/file.md\" or \"a/../b.md\").","Normalize or reject paths with GitUtils.normalizePath before inserting them into the map.","Catch BlobEditException and report the offending path to the API caller.","Validate file-name inputs at the UI/API boundary before constructing the commit payload."],"exampleFix":"// before\nnew BlobEdits(Set.of(), Map.of(\"/new/file.txt\", content)); // throws\n// after\nnew BlobEdits(Set.of(), Map.of(\"new/file.txt\", content));","handlingStrategy":"validation","validationCode":"Map<String, BlobContent> safe = new LinkedHashMap<>();\nfor (var e : newBlobs.entrySet()) {\n    String n = GitUtils.normalizePath(e.getKey());\n    if (n == null) throw new IllegalArgumentException(\"Invalid new path: \" + e.getKey());\n    safe.put(n, e.getValue());\n}","typeGuard":"boolean isValidNewPath(String p) {\n    return p != null && GitUtils.normalizePath(p) != null;\n}","tryCatchPattern":"try {\n    BlobEdits edits = new BlobEdits(oldPaths, newBlobs);\n} catch (BlobEditException e) {\n    // return 400-style error naming the bad path\n}","preventionTips":["Build new-file keys from validated file-name inputs only.","Never accept keys starting with '/' or containing '..'.","Normalize keys before inserting into newBlobs.","Sanitize API payloads that carry file paths."],"tags":["git","path-validation","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}