theonedev/onedev · error · IllegalArgumentException
Invalid parameter 'attachment-group'
Error message
Invalid parameter 'attachment-group'
What it means
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.
Source
Thrown at server-core/src/main/java/io/onedev/server/web/resource/AttachmentResource.java:68
private static final String PARAM_PROJECT = "project";
private static final String PARAM_ATTACHMENT_GROUP = "attachment-group";
private static final String PARAM_ATTACHMENT = "attachment";
public static final String PARAM_AUTHORIZATION = "authorization";
@Override
protected ResourceResponse newResourceResponse(Attributes attributes) {
PageParameters params = attributes.getParameters();
Long projectId = params.get(PARAM_PROJECT).toLong();
String attachmentGroup = params.get(PARAM_ATTACHMENT_GROUP).toString();
if (StringUtils.isBlank(attachmentGroup))
throw new IllegalArgumentException("Parameter 'attachment-group' has to be specified");
else if (attachmentGroup.contains(".."))
throw new IllegalArgumentException("Invalid parameter 'attachment-group'");
if (!SecurityUtils.isSystem()) {
Project project = OneDev.getInstance(ProjectService.class).load(projectId);
String authorization = params.get(PARAM_AUTHORIZATION).toOptionalString();
if (authorization == null
|| !new String(CryptoUtils.decrypt(Base64.decodeBase64(authorization)), UTF_8).equals(attachmentGroup)) {
Issue issue;
Build build;
if (OneDev.getInstance(PullRequestService.class).find(attachmentGroup) != null
|| OneDev.getInstance(CodeCommentService.class).findByUUID(attachmentGroup) != null) {
if (!SecurityUtils.canReadCode(project))
throw new UnauthorizedException();
} else if ((issue = OneDev.getInstance(IssueService.class).find(attachmentGroup)) != null) {
if (!SecurityUtils.canAccessIssue(issue))
throw new UnauthorizedException();
} else if ((build = OneDev.getInstance(BuildService.class).find(attachmentGroup)) != null) {
if (!SecurityUtils.canAccessProject(build.getProject()))View on GitHub (pinned to d44925c47c)
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
Example fix
// before GET /~resources/attachment?project=1&attachment-group=../42&attachment=f.txt // after GET /~resources/attachment?project=1&attachment-group=42&attachment=f.txt
Defensive patterns
Strategy: validation
Validate before calling
if (String(attachmentGroup).includes('..')) throw new Error('attachment-group must be a plain identifier, not a path: ' + attachmentGroup); Type guard
function isSafeAttachmentGroup(g) { return typeof g === 'string' && g.trim().length > 0 && !g.includes('..'); } Prevention
- 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
When it happens
Trigger: Calling the attachment resource with attachment-group containing a '..' substring, e.g. attachment-group=../other.
Common situations: 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.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/4f57269368e2a7b3.
Report an issue: GitHub.