Sploitus

Exploit for CVE-2025-30208 CVE-2025-30208 CVE-2025-31125 CVE-2025-31486

githubexploit · 2025-04-24

Exploit Code

README65 lines
## https://sploitus.com/exploit?id=511EC0F1-CA28-53A0-959B-779991C4F308
# CVE-2025-30208 & CVE-2025-31125 & CVE-2025-31486

# 1. Overview of Vulnerabilities

CVE-2025-30208, CVE-2025-31125, and CVE-2025-31486 are arbitrary file reading vulnerabilities in the Vite development server. These vulnerabilities allow attackers to bypass access controls through specific URL parameters, allowing them to read sensitive files on the server using the fs module. These three vulnerabilities can be considered a series of vulnerabilities, as their causes are very similar. CVE-2025-30208 affects versions as follows:
```
>=6.2.0, =6.1.0, =6.0.0, =5.0.0, =6.2.0, =6.1.0, =6.0.0, =5.0.0, =6.2.0, =6.1.0, =6.0.0, =5.0.0, /**],
```
From the official patch solutions, it seems that the vulnerability is addressed by strengthening the if statement in the `transformMiddleware` function, which checks the URL format and determines whether the service can access the requested path. Therefore, breakpoints are set in the `transformMiddleware` function, along with the process of parsing requests. ![](resources/image_5.png)

Since the project only produces compiled JavaScript files, breakpoints can be set for the entire file search function keywords. ![](resources/image_6.png)

A POC was performed, and the breakpoint was successfully set in the target function. It can be seen that after some variable assignments, the call process enters the `viteTransformMiddleware` function. After checking whether the request method is `GET` and whether the request is directed to the root directory and icon, the URL ends with the `?` removed by the `removeTimestampQuery` function. ```
/@fs/c:/windows/win.ini?import&raw?? ⬇
/@fs/c:/windows/win.ini?import&raw?```

The `cleanUrl()` function retrieves the URL without request parameters. At this point, the value of `withoutQuery` is `/@fs/c:/windows/win.ini`, so the code block where `if (!isSourceMap)` does not execute. Next, `publicDirInRoot` is used to determine whether the static resource directory is configured in the project’s root directory. `url.startsWith(publicPath)` checks whether the requested URL starts with the configured public path (e.g., /public/). When both conditions are met, `warnAboutExplicitPublicPathInUrl(url)` emits a warning. This usually indicates that developers have incorrectly added public paths in the code. Since the URL does not meet the conditions, the corresponding code block is skipped. The results of `rawRE.test(url)` and `urlRE.test(url)` are both False, so the result of `ensureServingAccess()` is not checked, and the logical expression is set to False, skipping the code block. In the subsequent if statement, the URL meets the regular expression defined by `ImportQueryRE`, and the if statement is executed. The URL is changed to `@/@fs/c:/windows/win.ini?raw` by the `removeImportQuery()` function, and then sent to the `transformRequest()` function.
```
/@fs/c:/windows/win.ini?import&raw? ⬇
/@fs/c:/windows/win.ini?raw
```

In the if statement where `isJSRequest(url)` is evaluated, it can be seen that the value of the HTTP Header `sec-fetch-dest` is also checked, which is `script`. If this value is `script`, the check can also be performed. This is why the POC is divided into two categories earlier: adding HTTP Headers and `?import&` are all used to pass the if statement’s check. (Actually, other methods can also be used to check, such as through `isHTMLProxy(url)` -> `/@fs/c:/windows/win.ini?html-proxy&raw??`)
![](resources/image_7.png)

After parameter processing, environment checks, cache key detection, and duplicate request detection, the `doTransform()` function is executed. ![](resources/image_8.png)

After checking the cache validity, the URL `@/@fs/c:/windows/win.ini?raw` is parsed to get the ID `c:/windows/win.ini?raw`. Then, the `loadAndTransform()` function is executed. ![](resources/image_9.png)

After some variable assignments, plugins are loaded based on the value of the ID. The order of plugin loading is as follows:

![](resources/image_10.png)

The cause of CVE-2025-30208 is that a carefully crafted URL is parsed and processed, passing through the `if (rawRE.test(id))` condition in the `assetPlugin` plugin, and then being sent to the `fsp.readFile()` function, resulting in the reading of local files. ![](resources/image_11.png)

## 4.2 CVE-2025-31125
The cause of CVE-2025-31125 is that the URL is parsed, satisfying the condition `id.endsWith(".wasm?init)` in the `wasmHelperPlugin` plugin. This leads to the URL being sent to the `fileToUrl$1()` function, and after `inlineRE$2.test(id)` is satisfied, it is sent to the `fsp.readFile()` function, resulting in the reading of local files. ![](resources/image_12.png)

## 4.3 CVE-2025-31486
CVE-2025-31486 is very similar to CVE-2025-31125. As can be seen from the analysis diagram for CVE-2025-31125, there are only two if statements in the `fileToDevUrl()` function that contain regular expression checks. The if statement where `inlineRE$2.test(id)` is located is the trigger point for CVE-2025-31125, and the subsequent if statement where `svgExtRE.test(id)` is located is the trigger point for CVE-2025-31486. The method of exploiting relative paths involves bypassing the verification in `ensureServingAccess()`. ![](resources/image_18.png)

After a URL enters the `isFileServingAllowed()` function, it first undergoes processing in `fsPathFromUrl()` using `cleanUrl()`, which removes the `?#` and subsequent content. For the URL in the POC, this results in the following change:
```
D:/PrograEnv/PythonEnv/pocsuite3/CVE-2025-30208/vuln-env/?/../../../../../../test.txt
```
    
    ⬇

D:/PrograEnv/PythonEnv/pocsuite3/CVE-2025-30208/vuln-env/
```

Then, the URL enters the `isFileLoadingAllowed()` function, where the `isUriFilePath()` method is used for verification, followed by a check with `isParentDirectory()`. ![](resources/image_19.png)

# 5. Vulnerability Fixes
## 5.1 CVE-2025-30208
Looking at the fix committed in commit `262b5ec`, the official approach was to remove the unnecessary `?` from the end of the parameter. This allows the parameter to successfully enter `ensureServingAccess()` when `rawRE.test(... || urlRE.test(...)) && !ensureServingAccess(...)`, thereby verifying whether the service allows access, avoiding unauthorized access due to short-circuit evaluation before the fix. ![](resources/image_13.png)

## 5.2 CVE-2025-31125
Looking at the fix committed in commit `5967313`, the official approach included adding a regular expression `inlineRE`. This allows the pattern `?inline=1.wasm?init` to be matched, allowing the parameter to normally enter `ensureServingAccess()` and be verified as to whether the service allows access. ![](resources/image_14.png)

## 5.3 CVE-2025-31486
Looking at the fix committed in commit `62d7e81`, the official fix includes two parts. The first part involves adding a new regular expression match for `.svg` to bypass the restriction. ![](resources/image_15.png)

The second part involves handling relative path reads by clearing the `id` parameter before sending it to `svgRe.test()`, ensuring that the parameters involved in `svgRe.test()` are consistent with those involved in the `file` concatenation. ![](resources/image_16.png)