dromara / dromara/lamp-cloud

Arbitrary file-existence and size oracle via chunk check (path traversal in `name`)

Open
#413 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
5.8k
Forks
1.8k
PR merge metrics
No merged PRs in 30d

Description

**Severity:** Medium · **CWE:** CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
## Summary

The chunk-check endpoint joins the request body's `name` field directly into a file path and returns whether that file exists and whether its size matches a caller-supplied value. Because `name` is not filtered, a caller can supply `../` sequences or an absolute path to probe for the existence of arbitrary files anywhere on the host and learn their exact size. The controller is marked `@Deprecated` and `@Hidden` (excluded from the Swagger UI) but is still mapped and reachable; no URI-level authorization is enforced for it.

## Vulnerability chain

| Stage | Component | Location |
| --------- | ------------------------------------------------------------ | ----------------------------- |
| Source | `POST /chunk/check`, body `FileChunkCheckDTO.name` / `size` / `chunkIndex` | `FileChunkController.java:73` |
| Transform | path = `Paths.get(uploadFolder, info.getName(), chunkIndex)` | `FileChunkController.java:77` |
| Sink | `new File(file).isFile()` + `target.length()` (boolean returned to caller) | `WebUploader.java:40-41` |

The `name` field is concatenated into the absolute path with no canonicalization. The controller then calls `chunkCheck`, which performs `new File(file).isFile()` and compares `target.length()` against the request-supplied `size`, returning the boolean result to the caller. A traversal in `name` escapes `uploadFolder`, so the boolean response and the size match together act as an arbitrary file-existence oracle that also reveals exact file size.

### Key code

The controller is reachable even though it is deprecated/hidden (`@RequestMapping("/chunk")`, `@Hidden`, `@Deprecated`):

```java
// lamp-base/lamp-base-controller/.../file/controller/FileChunkController.java:41,71
@RequestMapping("/chunk")
...
@RequestMapping(value = "/check", method = RequestMethod.POST)
@ResponseBody
public R chunkCheck(@RequestBody FileChunkCheckDTO info) {
log.info("info={}", info);
String uploadFolder = FileTypeUtil.getUploadPathPrefix(fileProperties.getLocal().getStoragePath());
boolean chunkCheck = wu.chunkCheck(Paths.get(uploadFolder, info.getName(), String.valueOf(info.getChunkIndex())).toString(), info.getSize());
return R.success(chunkCheck);
}
```

The `name` field is an unvalidated string:

```java
// lamp-base/lamp-base-entity/.../file/dto/chunk/FileChunkCheckDTO.java
public class FileChunkCheckDTO {
private Long size;
private String name; // unfiltered
private Integer chunkIndex;
}
```

The probe itself leaks existence and size:

```java
// lamp-base/lamp-base-controller/.../file/manager/WebUploader.java:38
public boolean chunkCheck(String file, Long size) {
java.io.File target = new java.io.File(file);
return target.isFile() && size == target.length(); // :41 — existence + size oracle
}
```

## Proof of Concept

Request-level only. By adjusting `size`, a caller can binary-search the exact length of any probed file. The endpoint is deprecated and `@Hidden` but still mapped:

```http
POST /chunk/check HTTP/1.1
Host:
Content-Type: application/json

{
"name": "../../../../../etc/passwd",
"chunkIndex": 0,
"size": 1234
}
```

A `true` response confirms the file exists and is exactly the supplied size; iterating `size` recovers the precise length of an arbitrary file.

## Impact

A remote attacker who can reach `/chunk/check` can enumerate the existence of arbitrary files on the host and determine their exact size, enabling sensitive-file discovery and information disclosure. The endpoint is deprecated and excluded from the API documentation, which makes it easy to forget it is still deployed and reachable; it is also not covered by URI-level authorization.

## Remediation

- Canonicalize the path (`Path.normalize()` / `getCanonicalFile()`) and reject any result outside `uploadFolder`; reject `name` values containing `..`, path separators, or absolute paths at the controller boundary.
- Remove the deprecated `@Hidden` `chunkCheck` endpoint, or hard-gate it behind authentication and authorization.
- Do not reflect a boolean file-existence result for attacker-controlled paths.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with FileChunkController.java:41,71-77, then inspect FileChunkCheckDTO.java and WebUploader.java:38-41 to trace how name and size reach the file check. Verify the /chunk/check endpoint cannot traverse outside uploadFolder or reveal arbitrary file existence and size, and account for its deprecated but still reachable mapping and missing URI authorization.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring-boot
Domain
api, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.