{"record":{"id":"3413c2da294932f0","repo":"theonedev/onedev","slug":"invalid-request-path-3413c2","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/MarkdownReportPage.java","lineNumber":45,"sourceCode":"import io.onedev.server.service.BuildService;\nimport io.onedev.server.service.ProjectService;\nimport io.onedev.server.web.component.markdown.MarkdownViewer;\nimport io.onedev.server.web.page.project.builds.detail.BuildDetailPage;\n\npublic class MarkdownReportPage extends BuildDetailPage {\n\n\tprivate static final String PARAM_REPORT = \"report\";\n\t\n\tprivate final String reportName;\n\t\n\tprivate final String filePath;\n\t\n\tpublic MarkdownReportPage(PageParameters params) {\n\t\tsuper(params);\n\t\t\n\t\treportName = params.get(PARAM_REPORT).toString();\n\t\tif (reportName.contains(\"..\"))\n\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\t\t\n\t\tList<String> pathSegments = new ArrayList<>();\n\t\tfor (int i=0; i<params.getIndexedCount(); i++) {\n\t\t\tString segment = params.get(i).toString();\n\t\t\tif (segment.contains(\"..\"))\n\t\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\t\t\tif (segment.length() != 0)\n\t\t\t\tpathSegments.add(segment);\n\t\t}\n\t\t\n\t\tfilePath = StringUtils.join(pathSegments, \"/\");\n\t\t\n\t\tif (!filePath.endsWith(\".md\")) {\n\t\t\tRequestCycle.get().scheduleRequestHandlerAfterCurrent(\n\t\t\t\t\tnew ResourceReferenceRequestHandler(new MarkdownReportDownloadResourceReference(), getPageParameters()));\n\t\t}\n\t}\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-report-markdown/src/main/java/io/onedev/server/plugin/report/markdown/MarkdownReportPage.java#L27-L63","documentation":"The MarkdownReportPage constructor validates the 'report' page parameter and rejects any value containing \"..\" with ExplicitException(\"Invalid request path\"). The report name is later joined into a filesystem path, so \"..\" would enable path traversal to arbitrary files. This is an intentional security rejection of a malformed URL.","triggerScenarios":"Opening a markdown report page URL (/projects/<p>/builds/<n>/markdown-reports/...) whose report name parameter contains '..', e.g. report=../other-report.","commonSituations":"Hand-written or stale links to report pages; scripts generating report URLs from untrusted input; encoded traversal attempts.","solutions":["Remove '..' from the report name in the URL.","Use the exact report name configured in the Publish Markdown Report step.","Regenerate the link from the build page's report listing instead of typing the path.","URL-encode the report name when building links programmatically."],"exampleFix":"// before\nString link = \"/projects/x/builds/5/markdown-reports/../../secret\";\n\n// after\nString link = \"/projects/x/builds/5/markdown-reports/docs\";","handlingStrategy":"validation","validationCode":"function validateReportPageParam(reportName) {\n  if (typeof reportName !== 'string' || reportName.includes('..')) {\n    throw new Error('invalid request path');\n  }\n}","typeGuard":"function isSafeReportName(v) {\n  return typeof v === 'string' && !v.includes('..');\n}","tryCatchPattern":null,"preventionTips":["Generate report page links from the build UI/API rather than by hand.","Reject or sanitize '..' in any user-supplied path before it reaches URLs.","URL-encode the report parameter."],"tags":["path-traversal","security","wicket-page"],"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"}