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

  1. Pass the plain group identifier (issue number, PR key, UUID, build number) without any path characters
  2. Normalize/validate the group value in your script before building the URL
  3. 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

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.