{"record":{"id":"3d446c60e511fe3d","repo":"theonedev/onedev","slug":"invalid-artifact-path","errorCode":null,"errorMessage":"Invalid artifact path","messagePattern":"Invalid artifact path","errorType":"validation","errorClass":"ExplicitException","httpStatus":400,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/ArtifactResource.java","lineNumber":54,"sourceCode":"@Consumes(MediaType.APPLICATION_JSON)\n@Produces(MediaType.APPLICATION_JSON)\n@Singleton\npublic class ArtifactResource {\n\t\n\tprivate final BuildService buildService;\n\t\n\t@Inject\n\tpublic ArtifactResource(BuildService buildService) {\n\t\tthis.buildService = buildService;\n\t}\n\t\n\t@Nullable\n\tprivate String normalizeArtifactPath(@Nullable String artifactPath) {\n\t\tif (StringUtils.isNotBlank(artifactPath)) {\n\t\t\tartifactPath = StringUtils.stripStart(artifactPath, \"/\");\n\t\t\tif (StringUtils.isNotBlank(artifactPath)) {\n\t\t\t\tif (artifactPath.contains(\"..\"))\n\t\t\t\t\tthrow new ExplicitException(\"Invalid artifact path\");\n\t\t\t\treturn artifactPath;\n\t\t\t}\n\t\t} \n\t\treturn null;\n\t}\n\t\n\t@Api(order=100, description = \"Get artifact info of specified path\")\n\t@Path(\"/{buildId}/infos{artifactPath:(/.*)?}\")\n    @GET\n    public ArtifactInfo getArtifactInfo(@PathParam(\"buildId\") Long buildId, \n\t\t\t\t\t\t\t\t\t\t@PathParam(\"artifactPath\") @Api(example = \"/path/to/directoryOrFile\") String artifactPath) {\n\t\tBuild build = buildService.load(buildId);\n\t\tif (!SecurityUtils.canAccessProject(build.getProject()))\n\t\t\tthrow new UnauthorizedException();\n\t\treturn buildService.getArtifactInfo(build, normalizeArtifactPath(artifactPath));\n    }\n\n\t@Api(order=200, description = \"Download artifact of specified path\")","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/ArtifactResource.java#L36-L72","documentation":"normalizeArtifactPath throws this ExplicitException when the supplied artifact path contains '..', which could allow directory traversal outside the build's artifact directory. It is a deliberate safety check rejecting any path that escapes the artifact root.","triggerScenarios":"Passing a path containing '..' (e.g. '../../etc/passwd', 'a/../../b') as artifactPath to getArtifactInfo, downloadArtifact, uploadArtifact, or deleteArtifact.","commonSituations":"Concatenating user-supplied file paths into artifact URLs; misconfigured CI variables that resolve to relative paths with '..'; path templates built with build-number placeholders inserted incorrectly.","solutions":["Remove '..' from the artifact path and address artifacts by their path under the build root","Validate/canonicalize the path in the calling script before calling the API","Reference the artifact via its exact published path shown in the build's artifacts tab"],"exampleFix":"// before\npath=\"../../secrets/key.jar\"\n// after\npath=\"target/app.jar\"","handlingStrategy":"validation","validationCode":"if (artifactPath && artifactPath.includes('..')) throw new Error('artifactPath must not contain ..');","typeGuard":"const isSafeArtifactPath = (p) => typeof p === 'string' && !p.includes('..');","tryCatchPattern":"try { upload(path) } catch (e) { if (/Invalid artifact path/.test(e.message)) { console.error('Path rejected: remove any \"..\" segments'); } else { throw e } }","preventionTips":["Always normalize and canonicalize paths before sending","Reject '..' segments in user-supplied artifact paths at the script level","Reference artifacts by paths as shown in the build artifacts listing"],"tags":["rest","artifact","path-traversal","validation"],"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-14T00:17:10.932Z"}