{"record":{"id":"e92cf1c5491a49e8","repo":"theonedev/onedev","slug":"invalid-request-path-e92cf1","errorCode":null,"errorMessage":"Invalid request path","messagePattern":"Invalid request path","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"warning","filePath":"server-plugin/server-plugin-report-unittest/src/main/java/io/onedev/server/plugin/report/unittest/TestArtifactResource.java","lineNumber":50,"sourceCode":"\npublic class TestArtifactResource extends AbstractResource {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate static final String PARAM_PROJECT = \"project\";\n\n\tprivate static final String PARAM_BUILD = \"build\";\n\n\tprivate static final String PARAM_REPORT = \"report\";\n\n\t@Override\n\tprotected ResourceResponse newResourceResponse(Attributes attributes) {\n\t\tvar params = attributes.getParameters();\n\t\tvar projectId = params.get(PARAM_PROJECT).toLong();\n\t\tvar buildNumber = params.get(PARAM_BUILD).toLong();\n\t\tString reportName = params.get(PARAM_REPORT).toString();\n\t\tif (reportName.contains(\"..\"))\n\t\t\tthrow new ExplicitException(\"Invalid request path\");\n\n\t\tif (!SecurityUtils.isSystem()) {\n\t\t\tvar project = OneDev.getInstance(ProjectService.class).load(projectId);\n\t\t\tvar build = OneDev.getInstance(BuildService.class).find(project, buildNumber);\n\t\t\tif (build == null) {\n\t\t\t\tthrow new EntityNotFoundException(String.format(\n\t\t\t\t\t\t\"Unable to find build (project: %s, build number: %d)\",\n\t\t\t\t\t\tproject.getPath(), buildNumber));\n\t\t\t}\n\t\t\tif (!SecurityUtils.canAccessReport(build, reportName))\n\t\t\t\tthrow new UnauthorizedException();\n\t\t}\n\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\");","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-report-unittest/src/main/java/io/onedev/server/plugin/report/unittest/TestArtifactResource.java#L32-L68","documentation":"The unit test artifact download resource validates the 'report' URL parameter and throws ExplicitException(\"Invalid request path\") when it contains \"..\". Because the report name feeds into a filesystem path under the build directory, traversal segments could expose files outside the report. This is an intentional security rejection of the request URL.","triggerScenarios":"Requesting test artifacts from the unittest report resource with a report name parameter containing '..', e.g. report=../artifacts.","commonSituations":"Scripts generating artifact download URLs from untrusted or concatenated paths; manual URL edits; stale templates building relative report names.","solutions":["Remove '..' from the report name in the URL.","Use the exact report name from the Publish Unit Test Report step.","URL-encode report names when constructing links programmatically.","Regenerate the download link from the build's test report page."],"exampleFix":"// before\nString url = \".../unittest-artifacts/\" + reportDir + \"/file.xml\"; // reportDir = \"../artifacts\"\n\n// after\nString url = \".../unittest-artifacts/\" + URLEncoder.encode(reportName, StandardCharsets.UTF_8) + \"/file.xml\";","handlingStrategy":"validation","validationCode":"function validateUnitTestReportName(reportName) {\n  if (!reportName || reportName.includes('..')) throw new Error('invalid request path');\n}","typeGuard":"function isSafeReportParam(v) {\n  return typeof v === 'string' && !v.includes('..');\n}","tryCatchPattern":null,"preventionTips":["Use the exact report name from the Publish Unit Test Report step.","URL-encode report parameters in generated links.","Avoid concatenating untrusted paths into artifact URLs."],"tags":["path-traversal","security","test-report"],"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"}