Service:
Node.js/ExpressRuby on RailsGrafanadev serversProtocol:
TCPPort:
3000Used for:
Hosting development web apps and dashboards like Node.js, Rails, and GrafanaPort 3000 has no single standard service — it is the de-facto default port for a whole family of web-app frameworks and tools. Node.js (Express), Ruby on Rails (rails server), and the create-react-app, Next.js, and Meteor development servers all bind 3000 out of the box, and in production Grafana serves its HTTP interface on 3000 by default. Because so many different things listen here, the first job on an open port 3000 isn’t to attack a known protocol — it’s to identify which web app is actually answering, and then assess that app. An internet-exposed development server (debug mode on, no auth, source and secrets leaking) or an unpatched Grafana behind 3000 is a classic finding.
Why It’s Open
Port 3000 is the number countless tutorials, scaffolds, and framework defaults reach for. npm start on an Express or create-react-app project, rails server (Puma), next dev, and Meteor all come up on http://localhost:3000 with no configuration. On a developer’s laptop that binds to localhost and no one else can reach it — but the same command on a cloud VM, a container, or a CI runner often binds 0.0.0.0:3000, and a permissive security group or a published Docker port (-p 3000:3000) quietly turns it into an internet-facing service.
The other big occupant is Grafana, whose built-in web server listens on 3000 unless you change it. Unlike a dev server, Grafana is meant to be a long-running production service, so an open 3000 in production is very often a Grafana instance. Other dashboards and self-hosted apps (Gitea, various Node APIs, assorted Docker images) also default to 3000. Where 3000 is answering, its neighbors are usually one scan away — check for plain HTTP on port 80, HTTPS on port 443, and the alternate HTTP/proxy port 8080.
Common Risks
- Exposed development servers. Dev builds run with debug mode on: verbose stack traces, source maps, hot-reload endpoints, and framework error pages that leak file paths, versions, and sometimes environment variables and database credentials. Rails development mode has historically shipped an in-browser console (
web-console/better_errors) that becomes remote code execution if the server is reachable. - No authentication or default credentials. Dev apps rarely have auth in front of them, and Grafana ships with
admin/admin— a default that operators routinely forget to change before exposing it. - Grafana-specific flaws. An unpatched Grafana on 3000 is exposed to unauthenticated path traversal (arbitrary file read of its own config and secrets), data-source proxy SSRF, and dashboard/snapshot information disclosure.
- Cleartext HTTP. Port 3000 is almost always plain HTTP with no TLS, so credentials, API tokens, and session cookies cross the wire in the clear.
- Information disclosure. Version banners,
/api/healthresponses, and shipped.js.mapsource maps hand an attacker the exact software and often the client-side logic and keys. - Stale, unpatched builds. Dev tooling and Grafana both move quickly; instances left listening on 3000 are frequently months or years behind on patches.
Want to save time on reporting?
Let PentestPad generate, track, and export your reports - automatically.

Enumeration & Testing
The whole game on port 3000 is identifying the app before you test it. Start with the service banner and the HTTP headers.
Detect the service and version
nmap -sV -p 3000 <target>Grab the response headers
curl -sI http://<target>:3000/Read the headers and root HTML to fingerprint the framework:
X-Powered-By: Express→ Node.js / ExpressX-Runtime,X-Request-Id, or a_<app>_sessioncookie → Ruby on Rails<div id="root">plus/static/js/assets → create-react-app;<div id="__next">plus/_next/→ Next.js- A
grafana_sessioncookie or a Grafana login page → Grafana
Fingerprint Grafana
curl -s http://<target>:3000/login | grep -i grafanacurl -s http://<target>:3000/api/healthGrafana’s /api/health returns JSON with database and version fields — a clean, unauthenticated version fingerprint that tells you immediately whether the instance is vulnerable.
Read the root page
curl -s http://<target>:3000/ | head -n 40Test Grafana path traversal (CVE-2021-43798)
Only against systems you are authorized to test:
curl --path-as-is http://<target>:3000/public/plugins/alertlist/../../../../../../../../etc/passwdMetasploit automates the same check across a range:
msfconsole -quse auxiliary/scanner/http/grafana_plugin_traversalset RHOSTS <target>runWeb application testing
Once you know the stack, drive it with OWASP ZAP or Burp Suite, and try admin / admin at Grafana’s /login. Log every exposed instance and successful login you confirm so it lands in the final pentest report instead of a scratch file.
What to Look For
| Checkpoint | What it means |
|---|---|
| Port 3000 reachable from outside localhost | A dev server or dashboard is exposed beyond its intended host |
X-Powered-By: Express / Rails / React / Next markers |
Identify the framework, then test that specific stack |
Grafana login page or /api/health JSON |
Grafana on 3000 — check version, default creds, and CVE-2021-43798 |
| Verbose stack traces or dev error pages | Debug mode is on — leaks paths, versions, sometimes secrets |
Source maps (.js.map) or /_next/, /static/ served |
Client-side source is recoverable; may expose API keys and logic |
admin / admin accepted on Grafana |
Full dashboard and data-source access |
| Plain HTTP with no redirect to HTTPS | Credentials and session cookies are sniffable on the wire |
Known CVEs and Exploits
For the frameworks themselves, an exposed port 3000 is usually a configuration problem — a debug server on a public interface with no authentication — rather than a single named CVE. The CVEs that matter on 3000 belong to whatever application is listening, and the most common named target by far is Grafana.
- CVE-2021-43798 — Grafana 8.0.0-beta1 through 8.3.0 unauthenticated path traversal via the plugin URL (
/public/plugins/<id>/../../../…). An attacker with no credentials reads arbitrary files, including Grafana’s owngrafana.iniandgrafana.db(data-source credentials and session tokens). CVSS 7.5. Automated by Metasploit’sauxiliary/scanner/http/grafana_plugin_traversaland Exploit-DB 50581. This is the signature Grafana-on-3000 bug. - CVE-2024-9264 — Grafana 11.0.0–11.2.2 SQL Expressions (experimental) command injection and local file inclusion leading to RCE. CVSS 8.8. Conditional: it needs a VIEWER-or-higher account and the
duckdbbinary present in Grafana’s PATH (not installed by default), so it is real but not a drive-by. - CVE-2023-3128 — Grafana authentication bypass (versions across 6.7.0–9.5.4). Grafana validated Azure AD accounts on the mutable, non-unique email claim, allowing account takeover. CVSS 9.8 — but only when Grafana is wired to Azure AD multi-tenant OAuth.
- CVE-2024-1863 — Sante PACS Server (a medical imaging server) token endpoint on port 3000: unauthenticated SQL injection in the
tokenparameter leading to remote code execution as NETWORK SERVICE. CVSS 9.8. A reminder that non-dev, non-Grafana products bind 3000 too. - CVE-2013-0928 — EMC AlphaStor Device Manager (
rrobotd.exe) on port 3000: OS command injection via a DCP “run command” operation, giving remote code execution on this legacy backup product. Metasploitexploit/windows/emc/alphastor_device_manager_exec; the related opcode 0x72 stack overflow is Exploit-DB 42720.
Do not confuse SaltStack “3000.x” (CVE-2020-11651 / CVE-2020-11652) with port 3000 — “3000” there is a Salt release version; the vulnerable salt-master service listens on 4505/4506, not on this port. It is a common false match on port-3000 write-ups.
Mitigation
- Never expose a development server to an untrusted network. Bind dev servers to
127.0.0.1, not0.0.0.0— for examplerails s -b 127.0.0.1, or setHOST=127.0.0.1for Node tooling. If the laptop-versus-cloud distinction is easy to miss, that’s exactly why accidental exposure is so common. - Front anything that must be reachable with a reverse proxy. Put nginx, Caddy, or Traefik in front with authentication and TLS on 443; never publish
:3000directly to the internet. - Turn off debug mode for anything internet-facing. Set
NODE_ENV=production/RAILS_ENV=productionso stack traces, in-browser consoles, and source maps are disabled. - Harden Grafana. Patch to a fixed release, change the default
admin/adminpassword, require authentication, disable anonymous access, and keep it off the public internet behind a VPN or IP allowlist. - Firewall port 3000 to trusted management ranges, and audit cloud security groups and container port mappings for an accidental
0.0.0.0:3000. - Inventory what actually runs on 3000. Because it could be any of a dozen apps, you can’t secure the port generically — you secure the specific service behind it.
Real-World Example
In December 2021 a path-traversal flaw in Grafana (CVE-2021-43798) was disclosed publicly as a zero-day while a fix was still being prepared. Because Grafana serves its UI on port 3000 by default and tens of thousands of instances were exposed to the internet, attackers began mass-scanning 3000 within hours — walking the /public/plugins/<id>/../../../ path to pull /etc/passwd, Grafana’s grafana.ini, and the grafana.db SQLite database, which holds data-source credentials and session tokens. No authentication was required. It’s the clearest illustration of the port-3000 lesson: the port itself is mundane, but whatever happens to be listening on it — here, an unpatched Grafana — is the real attack surface.
FAQ
What is port 3000 used for?
Port 3000 has no single standard service. It is the default port for many web-app development servers — Node.js (Express), Ruby on Rails (rails server), and the create-react-app, Next.js, and Meteor dev servers — and it is also Grafana’s default HTTP port. On an open 3000, the first step is to identify which of these is actually running.
Is port 3000 safe to leave open?
The port itself is harmless; the risk depends on what’s behind it. Bound to localhost on a developer’s machine it’s fine. Exposed to the internet, an open 3000 usually means either a development server running in debug mode with no authentication, or an unpatched Grafana — both worth locking down. Don’t publish 3000 to untrusted networks.
How do I find out what’s running on my port 3000?
Fingerprint it: curl -sI http://<host>:3000/ and nmap -sV -p 3000 <host>. Check the headers and HTML — X-Powered-By: Express points to Node, X-Runtime and Rails cookies point to Ruby on Rails, /_next/ or /static/js/ point to a React/Next dev server, and a grafana_session cookie or /api/health JSON points to Grafana.
Does Grafana use port 3000?
Yes. Grafana’s built-in web server listens on TCP 3000 by default. That’s why an open 3000 in a production environment is so often a Grafana instance, and why fingerprinting /api/health for its version is the fast first check.
Is port 3000 TCP or UDP?
TCP. The services that use 3000 (Node, Rails, dev servers, Grafana) all speak HTTP, which runs over TCP.
How do I secure or close port 3000?
Bind development servers to 127.0.0.1, put anything that must be reachable behind a reverse proxy with authentication and TLS, disable debug mode on production builds, patch Grafana and change its default credentials, and firewall the port to trusted hosts. If nothing needs it, stop the service and confirm the port is closed with a rescan.
TL;DR
- Service: no single standard — the default port for Node.js/Express, Ruby on Rails, and React/Next/Meteor dev servers, and for Grafana’s HTTP interface
- Default port: 3000/TCP (plain HTTP)
- Biggest risk: internet-exposed development servers (debug mode, no auth, source and secret leakage) and unpatched Grafana (CVE-2021-43798 path traversal)
- Mitigation: bind dev servers to localhost, reverse-proxy with auth and TLS, patch Grafana and change default creds, firewall port 3000