A critical React Native CLI vulnerability (CVE-2025-11953) allows unauthenticated remote command execution through the Metro development server. It’s rated CVSS 9.8 and affects widely used versions of @react-native-community/cli and its server API package—used across millions of developer machines. The patched lines are available now, but the defaults and common team setups still make accidental exposure far too easy. (jfrog.com)
Here’s the thing: this is not a “lab-only” bug. Metro binds to external interfaces by default, so a laptop on a coworking Wi‑Fi, a developer workstation in the cloud, or a misconfigured port forward can turn a local dev server into a network‑reachable target. That’s the doorway the exploit uses. (jfrog.com)
What changed in November 2025
On November 3, 2025, GitHub’s advisory database published a critical advisory for @react-native-community/cli and @react-native-community/cli-server-api. The issue was updated on November 13 with patched versions: 18.0.1, 19.1.2, and 20.0.0. The underlying problem: Metro exposes an endpoint that can be abused to execute arbitrary commands or binaries on the developer host. (github.com)
JFrog’s research team detailed how the bug is triggered via the /open-url endpoint, which unsafely forwards user input to the open() function from the open npm package. On Windows, an attacker can execute commands with fully controlled arguments; on macOS and Linux, arbitrary executables can run with more limited parameter control. (jfrog.com)
Am I affected? Quick audit in 3 minutes
First, check whether your project pulls in a vulnerable server API:
cd your/app
npm ls @react-native-community/cli-server-api
If you see versions from 4.8.0 up to 20.0.0‑alpha.2, you’re in the danger band. Most teams will inherit this via @react-native-community/cli in matching versions. The safest patched lines are 18.0.1, 19.1.2, and 20.0.0. (jfrog.com)
Also check if developers have a global install that could be used in scripts or path lookups:
npm ls -g @react-native-community/cli-server-api
If you’re on a framework that doesn’t use Metro as the dev server, you’re probably not affected—but verify, don’t assume. (jfrog.com)
How the exploit works (and why defaults make it worse)
Metro binds to 0.0.0.0 by default, which means it listens on all network interfaces. On a shared network or a cloud VM, the dev server may be reachable by anyone who can hit your machine’s IP and the Metro port (typically 8081). A crafted POST to /open-url triggers command execution via the open() sink. That’s it—no auth, no user interaction. (jfrog.com)
GitHub’s advisory confirms the affected and fixed versions and assigns the critical severity. Pair that with newsroom coverage calling out the two‑million‑downloads‑per‑week exposure, and you have the right level of urgency for leadership and SecOps. (github.com)
Primary fix: upgrade the CLI and server API
Pin your package versions to a patched line and redeploy your dev toolchain:
- @react-native-community/cli: upgrade to 18.0.1, 19.1.2, or 20.0.0 (or newer)
- @react-native-community/cli-server-api: upgrade to 18.0.1, 19.1.2, or 20.0.0 (or newer)
These are the versions that close the hole. If your RN stack is tied to an older CLI, track the backport discussions for your branch. Teams on RN 0.76.x previously asked for a 15.x backport—use that as a sanity check to plan your upgrade path, not as a reason to stall. (github.com)
Stopgap hardening if you can’t upgrade today
If an immediate upgrade isn’t possible, bind Metro to localhost so it’s not reachable from the network:
npx react-native start --host 127.0.0.1
You can wire this into your npm scripts. It’s not a substitute for the patch, but it sharply reduces risk while you move your branches. JFrog explicitly recommends this mitigation. (jfrog.com)
React Native CLI vulnerability: a zero‑trust dev server checklist
Use this five‑step checklist to prevent the next “local” dev server from becoming your soft spot:
- Default to localhost. For Metro and any dev server, bind to
127.0.0.1unless you have a documented reason not to. Add--host 127.0.0.1(or config equivalents) to scripts so it’s consistent on every machine. (jfrog.com) - Block at the edge. On laptops, enable the OS firewall and block inbound to ports like 8081 by default; on cloud workstations, restrict inbound security groups to the instance itself or a bastion.
- Rotate to patched lines fast. Create a security override in your dependency policy (e.g., Renovate/Dependabot) to prioritize the patched CLI versions across all active repos. Confirm via CI that transitive resolution lands on 18.0.1/19.1.2/20.0.0 or later. (github.com)
- Scan for exposed ports. Add a quick
netstatorlsofcheck to your developer onboarding and golden image pipelines. Verify Metro isn’t bound to anything but localhost. - Instrument for anomalies. If you build on hosted VMs, ship host telemetry (process start, child process chains) so command‑launch spikes from the dev account get flagged. It’s low‑effort and catches a lot more than this single CVE.
Data you can take to leadership
Why prioritize this today? Because the vulnerability is unauthenticated, network‑exploitable, and impacts a tool with roughly two million weekly downloads. In risk terms: high likelihood on shared networks, high impact on the developer’s host. GitHub’s CVSS is 9.8; the advisory and research posts detail Windows command execution and cross‑platform binary execution. (github.com)
If your org relies on cloud workstations or cross‑site dev, Metro’s external binding turns every session into an attack surface unless you change the default. This is the same pattern we’ve seen in other JavaScript ecosystem incidents—simple sink functions called with tainted input, then amplified by a default that broadens exposure.
People Also Ask
Is it safe to expose Metro to my LAN for device testing?
Only if you’ve patched to a safe version and you understand who else is on that LAN. Even then, prefer USB or reverse‑tunnel setups that authenticate access, and bind Metro to localhost plus an explicit tunnel. The vulnerability shows how “just the LAN” isn’t a boundary. (github.com)
How do I know if my project actually uses Metro?
If you run npm start or npx react-native start and see output about Metro bundler on port 8081, you’re using it. Many RN templates do. Frameworks that replace Metro may avoid this specific issue, but confirm via your scripts and package.json rather than assumptions. (jfrog.com)
What if I can’t move to 20.x yet?
Use the patched minors (18.0.1 or 19.1.2) where applicable, bind to localhost, and track your branch’s backport status. Put a deadline on the upgrade in your security exception register so it doesn’t sprawl. (github.com)
Practical steps: audit, patch, prove
Let’s get practical. Here’s a fast path we’ve used with client teams:
- Repo sweep. Use
npm lsand your SBOM tool to inventory @react-native-community/cli* across repos. Flag anything in the affected range and open blocking PRs to bump to 18.0.1, 19.1.2, or 20.0.0+ with lockfile updates. (github.com) - Script pinning. Update the dev scripts to include
--host 127.0.0.1and consider--portchanges if conflicts are common. Commit the scripts so every dev runs the same flags. (jfrog.com) - Golden image hardening. If you provision cloud workstations, set OS firewalls to block inbound 8081 and friends by default. Add a one‑liner validation in your Packer image or AMI test.
- CI evidence. Require a CI job that prints resolved versions of the CLI packages and fails on vulnerable ranges. Store the artifact as proof for audit.
- Developer comms. Push a short Slack/Teams note with the commands, the patched versions, and when the exception expires.
If you want a structured engagement to do this without burning sprint time, we can help. See how we run security hardening and incident‑readiness work in our service playbooks, and reach us via a quick intro.
Detecting possible compromise
What if a developer was running a vulnerable server on a shared network last week? You won’t always get perfect visibility, but you can still look for signs:
- Process tree anomalies. Shell or binary launches chained from the Metro process or node.exe during dev hours—especially on Windows—are suspicious given how this bug works. (jfrog.com)
- Unusual outbound traffic. If host EDR is in place, check for new connections immediately following Metro starts.
- Persistence checks. Review user startup folders and common autoruns locations for anything created during dev sessions.
No signal doesn’t prove safety, but with the patch and localhost binding in place, your risk drops dramatically.
Why this keeps happening in JavaScript tooling
Zooming out, this isn’t an isolated slip. Earlier this year, high‑impact vulnerabilities in the JavaScript ecosystem reminded us how a tiny helper can torch reliability—like the expr‑eval parser bug many teams had to rush‑patch. If you missed that incident, start with our rapid fix playbook for the expr‑eval vulnerability. (techradar.com)
Supply chain attacks and configuration gotchas thrive where defaults are permissive and developer UX hides network exposure. The fix pattern is boring but effective: pin versions, turn risky defaults off, and add light‑touch detection. You don’t need a wholesale platform rewrite—just consistent hygiene.
Edge cases and gotchas
Windows vs. macOS/Linux behavior. Research shows full command execution on Windows and arbitrary binary execution (with limited params) on macOS/Linux. Treat all platforms as high risk and patch regardless. (jfrog.com)
Stale global installs. Even if your repo is clean, a developer with a global vulnerable CLI could inadvertently start Metro in a risky mode. Include the global check in onboarding and quarterly hygiene.
Per‑app overrides. Some teams pass --host in local scripts but forget shared templates or monorepo workspaces. Standardize your start scripts, or you’ll drift back to default exposure. (jfrog.com)
What to do next
- Patch to 18.0.1, 19.1.2, or 20.0.0+ across all RN projects today. Prove it in CI. (github.com)
- Force localhost binding in scripts (
--host 127.0.0.1) and block inbound ports on laptops and cloud workstations. (jfrog.com) - Audit global installs on developer machines and golden images.
- Add a lightweight port/process check to your golden image and onboarding docs.
- Review your broader security posture—token scope, CI secrets, and outage drills—to cut cascade risk. For a practical primer, see our notes on tightening npm tokens in CI and our resilience playbook for incident prep.
If you need help
We’ve done this kind of triage for fast‑moving teams: version pinning, script hardening, and golden image updates without breaking developer flow. Explore our security hardening engagements and what we do, or contact us to schedule a quick RN toolchain audit. We’re easy to reach.
FAQ for decision‑makers
What’s the real business impact? A compromised developer host can leak credentials, sign malicious builds, or commit poisoned code. Even if this bug lives in “dev tools,” it’s a production‑grade risk.
Is there evidence of exploitation in the wild? As of mid‑November reporting, researchers said no confirmed public exploits, but the ease of attack and huge install base warrant an urgent patch cycle. Treat it as a fire drill you can finish in a day. (techradar.com)
Will this patch break our workflow? The patched versions are drop‑in for most projects. Where an older CLI line blocks you, use the fixed minors (18.0.1/19.1.2) or track an appropriate backport issue while binding to localhost. (github.com)
Final take
The React Native CLI vulnerability is the latest reminder that developer tooling is part of your attack surface. The fixes exist, the mitigations are simple, and the cost of doing nothing is a compromised developer workstation. Patch the packages, force localhost, and make it muscle memory in your templates. Then keep rolling: version hygiene, minimal network exposure, and quick detection are the habits that keep “local” bugs local.
