theonedev/onedev · warning · ExplicitException

Invalid request path

Error message

Invalid request path

What it means

OneDev's markdown report download resource rejects a report name URL parameter that contains ".." by throwing ExplicitException("Invalid request path"). This is a path-traversal guard: the report name is joined into a filesystem path under the build's report directory, and ".." segments could escape that directory and read arbitrary files. The error is intentional and user-facing, meaning the URL itself is malformed/malicious, not that the server is broken.

Source

Thrown at server-plugin/server-plugin-report-markdown/src/main/java/io/onedev/server/plugin/report/markdown/MarkdownReportDownloadResource.java:61

		Long buildNumber = params.get(PARAM_BUILD).toOptionalLong();
		
		if (buildNumber == null)
			throw new IllegalArgumentException("build number has to be specified");
		
		Build build = OneDev.getInstance(BuildService.class).find(project, buildNumber);

		if (build == null) {
			String message = String.format("Unable to find build (project: %s, build number: %d)", 
					project.getPath(), buildNumber);
			throw new EntityNotFoundException(message);
		}
		
		String reportName = params.get(PARAM_REPORT).toOptionalString();
		
		if (reportName == null)
			throw new IllegalArgumentException("Markdown report name has to be specified");
		if (reportName.contains(".."))
			throw new ExplicitException("Invalid request path");
		
		if (!SecurityUtils.canAccessReport(build, reportName))
			throw new UnauthorizedException();
			
		List<String> pathSegments = new ArrayList<>();
		for (int i = 0; i < params.getIndexedCount(); i++) {
			String pathSegment = params.get(i).toString();
			if (pathSegment.contains(".."))
				throw new ExplicitException("Invalid request path");
			if (pathSegment.length() != 0)
				pathSegments.add(pathSegment);
		}
		
		String markdownPath = Joiner.on("/").join(pathSegments);
		
		File buildDir = build.getDir();
		File reportDir = new File(buildDir, PublishMarkdownReportStep.CATEGORY + "/" + reportName);
		

View on GitHub (pinned to d44925c47c)

Solutions

  1. Remove any '..' sequences from the report name used to build the URL.
  2. Use the exact report name configured in the Publish Markdown Report build step.
  3. URL-encode path parameters in scripts so '..' segments are not silently introduced.
  4. If a legitimate report is being blocked, rename the report so it contains no dots-pairs.

Example fix

// before
String url = baseUrl + "/~builds/" + buildId + "/markdown-reports/" + relativeDir + "/report.md";

// after
String safeReport = relativeDir.replace("..", "");
String url = baseUrl + "/~builds/" + buildId + "/markdown-reports/" + URLEncoder.encode(safeReport, StandardCharsets.UTF_8) + "/report.md";
Defensive patterns

Strategy: validation

Validate before calling

function validateReportName(reportName) {
  if (!reportName || reportName.includes('..')) throw new Error('invalid report name: ' + reportName);
  return reportName;
}

Type guard

function isSafeSegment(s) {
  return typeof s === 'string' && s.length > 0 && !s.includes('..');
}

Prevention

When it happens

Trigger: Hitting the markdown report download resource (e.g. /~builds/<id>/markdown-reports/...) with a 'report' URL parameter containing a '..' sequence, such as report=..%2Fsecret or report=foo/../../etc/passwd.

Common situations: Hand-crafted or bookmarked download URLs with wrong report paths; scripts that build the URL by concatenating untrusted path values; browser-encoded traversal attempts; typos where '..' is accidentally left in a generated link.

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/18b74623b9ccf2d4. Report an issue: GitHub.