{"record":{"id":"18b74623b9ccf2d4","repo":"theonedev/onedev","slug":"invalid-request-path-18b746","errorCode":null,"errorMessage":"Invalid request path","messagePattern":"Invalid request path","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"warning","filePath":"server-plugin/server-plugin-report-markdown/src/main/java/io/onedev/server/plugin/report/markdown/MarkdownReportDownloadResource.java","lineNumber":61,"sourceCode":"\t\tLong buildNumber = params.get(PARAM_BUILD).toOptionalLong();\n\t\t\n\t\tif (buildNumber == null)\n\t\t\tthrow new IllegalArgumentException(\"build number has to be specified\");\n\t\t\n\t\tBuild build = OneDev.getInstance(BuildService.class).find(project, buildNumber);\n\n\t\tif (build == null) {\n\t\t\tString message = String.format(\"Unable to find build (project: %s, build number: %d)\", \n\t\t\t\t\tproject.getPath(), buildNumber);\n\t\t\tthrow new EntityNotFoundException(message);\n\t\t}\n\t\t\n\t\tString reportName = params.get(PARAM_REPORT).toOptionalString();\n\t\t\n\t\tif (reportName == null)\n\t\t\tthrow new IllegalArgumentException(\"Markdown report name has to be specified\");\n\t\tif (reportName.contains(\"..\"))\n\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\t\t\n\t\tif (!SecurityUtils.canAccessReport(build, reportName))\n\t\t\tthrow new UnauthorizedException();\n\t\t\t\n\t\tList<String> pathSegments = new ArrayList<>();\n\t\tfor (int i = 0; i < params.getIndexedCount(); i++) {\n\t\t\tString pathSegment = params.get(i).toString();\n\t\t\tif (pathSegment.contains(\"..\"))\n\t\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\t\t\tif (pathSegment.length() != 0)\n\t\t\t\tpathSegments.add(pathSegment);\n\t\t}\n\t\t\n\t\tString markdownPath = Joiner.on(\"/\").join(pathSegments);\n\t\t\n\t\tFile buildDir = build.getDir();\n\t\tFile reportDir = new File(buildDir, PublishMarkdownReportStep.CATEGORY + \"/\" + reportName);\n\t\t","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-report-markdown/src/main/java/io/onedev/server/plugin/report/markdown/MarkdownReportDownloadResource.java#L43-L79","documentation":"OneDev's markdown report download resource rejects a report name URL parameter that contains \"..\" by throwing ExplicitException(\"Invalid request path\"). This is a path-traversal guard: the report name is joined into a filesystem path under the build's report directory, and \"..\" segments could escape that directory and read arbitrary files. The error is intentional and user-facing, meaning the URL itself is malformed/malicious, not that the server is broken.","triggerScenarios":"Hitting the markdown report download resource (e.g. /~builds/<id>/markdown-reports/...) with a 'report' URL parameter containing a '..' sequence, such as report=..%2Fsecret or report=foo/../../etc/passwd.","commonSituations":"Hand-crafted or bookmarked download URLs with wrong report paths; scripts that build the URL by concatenating untrusted path values; browser-encoded traversal attempts; typos where '..' is accidentally left in a generated link.","solutions":["Remove any '..' sequences from the report name used to build the URL.","Use the exact report name configured in the Publish Markdown Report build step.","URL-encode path parameters in scripts so '..' segments are not silently introduced.","If a legitimate report is being blocked, rename the report so it contains no dots-pairs."],"exampleFix":"// before\nString url = baseUrl + \"/~builds/\" + buildId + \"/markdown-reports/\" + relativeDir + \"/report.md\";\n\n// after\nString safeReport = relativeDir.replace(\"..\", \"\");\nString url = baseUrl + \"/~builds/\" + buildId + \"/markdown-reports/\" + URLEncoder.encode(safeReport, StandardCharsets.UTF_8) + \"/report.md\";","handlingStrategy":"validation","validationCode":"function validateReportName(reportName) {\n  if (!reportName || reportName.includes('..')) throw new Error('invalid report name: ' + reportName);\n  return reportName;\n}","typeGuard":"function isSafeSegment(s) {\n  return typeof s === 'string' && s.length > 0 && !s.includes('..');\n}","tryCatchPattern":null,"preventionTips":["Never interpolate raw path values into report URLs.","URL-encode all path parameters when building links.","Keep report names simple identifiers without dots-pairs."],"tags":["path-traversal","security","url-parameter"],"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"}