{"record":{"id":"0502749399cd450f","repo":"theonedev/onedev","slug":"invalid-request-path-050274","errorCode":null,"errorMessage":"Invalid request path","messagePattern":"Invalid request path","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"warning","filePath":"server-core/src/main/java/io/onedev/server/web/page/project/builds/detail/report/BuildReportPage.java","lineNumber":20,"sourceCode":"\nimport io.onedev.commons.utils.ExplicitException;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\n\nimport io.onedev.server.model.Build;\nimport io.onedev.server.security.SecurityUtils;\nimport io.onedev.server.web.page.project.builds.detail.BuildDetailPage;\n\npublic abstract class BuildReportPage extends BuildDetailPage {\n\n\tprivate static final String PARAM_REPORT = \"report\";\n\n\tprivate final String reportName;\n\t\n\tpublic BuildReportPage(PageParameters params) {\n\t\tsuper(params);\n\t\treportName = params.get(PARAM_REPORT).toString();\n\t\tif (reportName.contains(\"..\"))\n\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\t}\n\t\n\t@Override\n\tprotected boolean isPermitted() {\n\t\treturn SecurityUtils.canAccessReport(getBuild(), reportName);\n\t}\n\t\n\tpublic String getReportName() {\n\t\treturn reportName;\n\t}\n\n\tpublic static PageParameters paramsOf(Build build, String reportName) {\n\t\tPageParameters params = paramsOf(build);\n\t\tparams.add(PARAM_REPORT, reportName);\n\t\treturn params;\n\t}\n\t\n}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/page/project/builds/detail/report/BuildReportPage.java#L2-L38","documentation":"BuildReportPage takes the report name directly from the URL. To prevent path traversal against the report storage directory, the constructor rejects any report name containing '..' and throws ExplicitException('Invalid request path'). This is a deliberate security check, not a data error.","triggerScenarios":"Requesting a build report page where the PARAM_REPORT path segment contains '..' (e.g. /~builds/5/reports/../../secrets), typically crafted URLs or links generated with unescaped report names.","commonSituations":"Security scanning / pen-testing OneDev; a custom integration that interpolates raw report names into URLs; clicking a tampered link.","solutions":["Remove '..' from the report name in the URL; use the exact report name as shown on the build page.","URL-encode or validate report names in any integration that generates report links.","If this appears unexpectedly, treat it as a potential probing attempt and check access logs."],"exampleFix":"// before\nString url = \"/~builds/5/reports/\" + userInput; // userInput=\"../x\"\n// after\nString url = \"/~builds/5/reports/\" + URLEncoder.encode(sanitizeReportName(userInput), StandardCharsets.UTF_8);","handlingStrategy":"validation","validationCode":"if (reportName == null || reportName.contains(\"..\") || reportName.isBlank()) {\n    throw new IllegalArgumentException(\"Invalid report name\");\n}","typeGuard":"static boolean isSafeSegment(String s) { return s != null && !s.contains(\"..\") && !s.isBlank(); }","tryCatchPattern":"try {\n    // open report page\n} catch (ExplicitException e) {\n    // surface e.getMessage() to the user, do not retry\n}","preventionTips":["URL-encode report names when building links.","Reject path segments containing '..' at input boundaries.","Use report names exactly as produced by the build's publish-report step."],"tags":["onedev","security","path-traversal","url"],"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"}