{"record":{"id":"4f57269368e2a7b3","repo":"theonedev/onedev","slug":"invalid-parameter-attachment-group","errorCode":null,"errorMessage":"Invalid parameter 'attachment-group'","messagePattern":"Invalid parameter 'attachment-group'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/resource/AttachmentResource.java","lineNumber":68,"sourceCode":"\tprivate static final String PARAM_PROJECT = \"project\";\n\t\n\tprivate static final String PARAM_ATTACHMENT_GROUP = \"attachment-group\";\n\t\n\tprivate static final String PARAM_ATTACHMENT = \"attachment\";\n\t\n\tpublic static final String PARAM_AUTHORIZATION = \"authorization\";\n\t\n\t@Override\n\tprotected ResourceResponse newResourceResponse(Attributes attributes) {\n\t\tPageParameters params = attributes.getParameters();\n\t\t\n\t\tLong projectId = params.get(PARAM_PROJECT).toLong();\n\t\tString attachmentGroup = params.get(PARAM_ATTACHMENT_GROUP).toString();\n\t\t\n\t\tif (StringUtils.isBlank(attachmentGroup))\n\t\t\tthrow new IllegalArgumentException(\"Parameter 'attachment-group' has to be specified\");\n\t\telse if (attachmentGroup.contains(\"..\"))\n\t\t\tthrow new IllegalArgumentException(\"Invalid parameter 'attachment-group'\");\n\n\t\tif (!SecurityUtils.isSystem()) {\n\t\t\tProject project = OneDev.getInstance(ProjectService.class).load(projectId);\n\t\t\t\n\t\t\tString authorization = params.get(PARAM_AUTHORIZATION).toOptionalString();\n\t\t\tif (authorization == null \n\t\t\t\t\t|| !new String(CryptoUtils.decrypt(Base64.decodeBase64(authorization)), UTF_8).equals(attachmentGroup)) {\n\t\t\t\tIssue issue;\n\t\t\t\tBuild build;\n\t\t\t\tif (OneDev.getInstance(PullRequestService.class).find(attachmentGroup) != null\n\t\t\t\t\t\t|| OneDev.getInstance(CodeCommentService.class).findByUUID(attachmentGroup) != null) {\n\t\t\t\t\tif (!SecurityUtils.canReadCode(project))\n\t\t\t\t\t\tthrow new UnauthorizedException();\n\t\t\t\t} else if ((issue = OneDev.getInstance(IssueService.class).find(attachmentGroup)) != null) {\n\t\t\t\t\tif (!SecurityUtils.canAccessIssue(issue))\n\t\t\t\t\t\tthrow new UnauthorizedException();\n\t\t\t\t} else if ((build = OneDev.getInstance(BuildService.class).find(attachmentGroup)) != null) {\n\t\t\t\t\tif (!SecurityUtils.canAccessProject(build.getProject()))","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/resource/AttachmentResource.java#L50-L86","documentation":"AttachmentResource rejects an 'attachment-group' value containing '..' with IllegalArgumentException 'Invalid parameter attachment-group'. Like the artifact resource, this is a path-safety check preventing the group value from being used for traversal when resolved later.","triggerScenarios":"Calling the attachment resource with attachment-group containing a '..' substring, e.g. attachment-group=../other.","commonSituations":"Malformed or attacker-crafted URLs (often security scanners); scripts concatenating path components into the group parameter; copy errors where directory separators leaked into the value.","solutions":["Pass the plain group identifier (issue number, PR key, UUID, build number) without any path characters","Normalize/validate the group value in your script before building the URL","If a scanner flagged this, treat it as expected: the server blocks traversal by design"],"exampleFix":"// before\nGET /~resources/attachment?project=1&attachment-group=../42&attachment=f.txt\n// after\nGET /~resources/attachment?project=1&attachment-group=42&attachment=f.txt","handlingStrategy":"validation","validationCode":"if (String(attachmentGroup).includes('..')) throw new Error('attachment-group must be a plain identifier, not a path: ' + attachmentGroup);","typeGuard":"function isSafeAttachmentGroup(g) { return typeof g === 'string' && g.trim().length > 0 && !g.includes('..'); }","tryCatchPattern":null,"preventionTips":["Pass identifiers (number/UUID), never paths, as attachment-group","Sanitize inputs that flow into attachment URLs","Treat server rejection of '..' values as expected security behavior"],"tags":["security","path-traversal","attachment"],"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"}