logo

Port 9000 – PHP-FPM, SonarQube & Portainer (Multiplexed Dev/Infra Port)

Service:

PHP-FPM (FastCGI)SonarQubePortainerClickHouseMinIOXdebug

Protocol:

TCP

Port:

9000

Used for:

A shared default port for FastCGI (PHP-FPM), the SonarQube web UI, the Portainer Docker console, and data-infrastructure services like ClickHouse and MinIO, with no single owning protocol.

Port 9000 has no single owning service — it is a heavily multiplexed default shared by a handful of very different programs, and the whole job on an open 9000 is to work out which one is answering before you test it. By default, PHP-FPM (the FastCGI Process Manager) listens on 127.0.0.1:9000, the SonarQube code-quality platform serves its web UI here, and Portainer historically exposes its Docker management console on 9000. Data-infrastructure tools pile on too: ClickHouse speaks its native protocol on 9000, MinIO long served its S3 API and console here, Hadoop HDFS often sets fs.defaultFS to 9000, and Xdebug (v2) uses 9000 as its DBGp debugger port. These services have almost nothing in common — one is a raw FastCGI socket, one is a Java web app, one is a container-orchestration API — so fingerprinting comes first, and the risk you report depends entirely on what you find.

Why It’s Open

Port 9000 is open because a developer tool, a code-analysis server, or a piece of data infrastructure defaulted to it. The most common occupants, roughly in order of how often they matter to a pentest:

  • PHP-FPM (FastCGI) — the default. PHP’s FastCGI Process Manager binds 127.0.0.1:9000 and is meant to be spoken to only by a local web server (nginx/Apache) over the FastCGI protocol. When that socket is reachable from the network instead of localhost, it becomes a direct code-execution surface (see below).
  • SonarQube — the open-source code-quality/SAST platform serves its web UI and REST API on 9000 out of the box, and ships with a well-known default admin/admin login.
  • Portainer — the Docker/Kubernetes management UI historically exposes its console and API on 9000 (HTTPS moved to 9443 in later builds). Whoever controls Portainer controls the container host.
  • ClickHouse — the columnar OLAP database uses 9000 for its native TCP protocol (its HTTP interface is on 8123), so an open 9000 on a data host is frequently a ClickHouse server.
  • MinIO — the S3-compatible object store historically served both its API and console on 9000.
  • Hadoop / Xdebug / Kentico / assorted internal apps — HDFS NameNode RPC (fs.defaultFS) is commonly set to 9000, Xdebug 2 listens on 9000 for step-debugging, and countless custom apps grab 9000 because it’s memorable and rarely reserved.

On a developer laptop, an open 9000 is usually PHP-FPM or an Xdebug listener bound to localhost. On a server or cloud VM, it is far more likely to be SonarQube, Portainer, ClickHouse, or MinIO — and if any of those is reachable from an untrusted network, it deserves immediate attention.

Port 9000 is worth distinguishing from the nearby “dev” ports, which are almost always plain HTTP web apps: port 8080 (HTTP-alternate/proxy), port 8000 (dev web servers and APIs), port 8888 (dev HTTP, Jupyter), and port 3000 (Node/React dev servers). Those you can reasonably treat as “a web app to fingerprint.” Port 9000 is different: it’s a multiplex of a raw FastCGI socket, a SAST server, a container-orchestration API, and data stores, so you can’t assume HTTP at all until you’ve probed it.

Common Risks

  • Exposed FastCGI = direct code execution. The FastCGI protocol has no authentication. If PHP-FPM’s 9000 socket is reachable off-host, anyone can send FastCGI requests that set SCRIPT_FILENAME and pass PHP directives (e.g. auto_prepend_file = php://input) to execute arbitrary PHP or disclose local files — no CVE required, just a misconfigured bind address.
  • SonarQube default credentials and unauth API. A fresh SonarQube left on admin/admin hands over every analyzed project’s source, findings, and stored tokens; some versions also leak configured credentials through unauthenticated API endpoints.
  • Portainer takeover. An uninitialized Portainer instance, or one running a vulnerable build, can be hijacked by an unauthenticated attacker who creates the first admin account — full control of the Docker/Kubernetes environment behind it.
  • Data-store exposure. A ClickHouse or MinIO instance on 9000 with default or no credentials exposes entire datasets and object buckets to read (and often write).
  • Information disclosure. Status pages, version banners, and debug/DBGp endpoints on 9000 leak versions, stack details, and internal paths that tell an attacker exactly which exploit to reach for.
  • Wrong assumptions. Because so many unrelated services share 9000, treating it as “just a dev port” is how an internet-facing FastCGI socket or admin console gets missed.

Want to save time on reporting?

Let PentestPad generate, track, and export your reports - automatically.

logo-cta

Enumeration & Testing

The entire methodology on port 9000 is fingerprint first, then test the identified service. Start with a version scan, grab the banner, and check whether it answers as HTTP or as a raw binary protocol — then branch.

Detect the service and version

Terminal window
nmap -sV -p 9000 <target>
nmap -sV --script "http-title,http-headers" -p 9000 <target>

Grab the raw banner

Terminal window
nc -nv <target> 9000

Check whether it answers as HTTP (SonarQube, Portainer, MinIO, custom app)

Terminal window
curl -sI http://<target>:9000/

Read the Server/X-Powered-By headers. A response is your first fork: an HTTP banner points to a web app to fingerprint; no HTTP response but an open port often means a raw FastCGI or ClickHouse listener.

Identify SonarQube

Terminal window
# Version/health with no auth
curl -s http://<target>:9000/api/system/status
# Does it leak configured settings/credentials without auth? (CVE-2020-27986)
curl -s http://<target>:9000/api/settings/values

A {"status":"UP", ...} JSON body confirms SonarQube. Then try the default admin/admin login in the browser.

Identify Portainer

Terminal window
# Portainer returns its version here
curl -s http://<target>:9000/api/system/status

If the instance is uninitialized, the admin-bootstrap endpoint (/api/users/admin/init) may still be reachable — see the CVE note below before touching it.

Probe a raw FastCGI (PHP-FPM) listener

The FastCGI protocol isn’t HTTP, so curl won’t fingerprint it. Use cgi-fcgi (from the libfcgi-bin package) to speak FastCGI directly:

Terminal window
SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
cgi-fcgi -bind -connect <target>:9000

A FastCGI reply (rather than a connection error) confirms an exposed PHP-FPM socket — a critical finding, because FastCGI has no auth. Do not weaponize beyond proving reachability without authorization.

Identify ClickHouse (native protocol on 9000)

Terminal window
clickhouse-client --host <target> --port 9000 --query "SELECT version()"

A version string (especially against the default default user with no password) confirms an exposed ClickHouse server.

Log every open port 9000, the service you positively identified, the version, and any default-credential or unauthenticated-endpoint result you confirm, so the evidence lands in the pentest report rather than a scratch terminal you’ll lose.

What to Look For

Checkpoint What it means
Open port, no HTTP response, FastCGI reply to cgi-fcgi Exposed PHP-FPM — unauthenticated FastCGI means direct PHP execution / file disclosure. Critical.
/api/system/status returns {"status":"UP"} SonarQube — check for admin/admin and unauth settings leakage
/api/settings/values returns config without auth SonarQube credential disclosure (CVE-2020-27986)
HTTP UI/API identifying as Portainer Docker/K8s console — verify it’s initialized and patched, or it’s an admin-takeover target
Native-protocol handshake / SELECT version() works ClickHouse (or MinIO S3 API) — test default/blank credentials and data access
Server: / X-Powered-By: header on 9000 A custom or dev web app — fingerprint and test that specific stack
Version banner on any of the above Maps directly to known CVEs for that product and version

Known CVEs and Exploits

There is no “port 9000” CVE — the bugs that matter belong to whichever service is listening, and the single highest-impact issue here (an exposed FastCGI socket) is a misconfiguration, not a CVE: PHP-FPM’s FastCGI protocol has no authentication, so a 9000 socket reachable off-host is remote code execution regardless of patch level. The verified, correctly-scoped CVEs for the common occupants:

  • CVE-2019-11043 — the marquee PHP-FPM bug. A buffer underflow in the FPM module (PHP 7.1.x < 7.1.33, 7.2.x < 7.2.24, 7.3.x < 7.3.11) lets an attacker write past allocated buffers into FastCGI protocol space and achieve remote code execution. CVSS 9.8. Reachability caveat: this specific bug is triggered through the nginx front-end (ports 80/443) in configs that use fastcgi_split_path_info with a PATH_INFO variable and no file-existence check — not by hitting 9000 directly. It’s weaponized as neex’s Go tool phuip-fpizdam and published as Exploit-DB 47553 (“PHP-FPM + Nginx - Remote Code Execution”). A raw, network-exposed 9000 FastCGI socket is a separate and arguably worse problem that needs no CVE at all.
  • CVE-2020-27986SonarQube unauthenticated credential disclosure. The /api/settings/values endpoint can be reached without authentication and returns cleartext SMTP, SVN, and GitLab credentials. CVSS 7.5. Note: this record is marked DISPUTED — the vendor argues it’s the administrator’s responsibility to lock the instance down — but the exposure is real if the endpoint is reachable.
  • CVE-2026-55761Portainer unauthenticated admin takeover. In Portainer CE 2.39.0–2.39.3 and 2.40.0 through 2.42.x, the unauthenticated /api/restore and /api/users/admin/init endpoints stay reachable during the five-minute setup window on an uninitialized instance, letting a network attacker restore a crafted backup or create the first administrator and gain full control. CVSS 5.9. Fixed in 2.39.4 and 2.43.0.

Removed as wrong-service / mislabeled. The previous version of this page listed CVEs that do not belong to any port-9000 service and have been deleted: CVE-2023-35390 was labeled a “SonarQube authentication bypass” but is actually a .NET / Visual Studio remote-code-execution bug with no SonarQube involvement; CVE-2022-0540 is a genuine Atlassian Jira (Seraph) authentication bypass, but Jira defaults to port 8080, not 9000 — the “often runs on port 9000” claim was false; and CVE-2018-1000226 is a real Cobbler XMLRPC access-control flaw whose /cobbler_api endpoint does not live on port 9000. Always verify a CVE against its NVD record and confirm the affected product actually runs on the port before trusting it.

Mitigation

  • Identify the real service first. You cannot secure port 9000 generically — fingerprint what’s answering, then harden that specific thing.
  • PHP-FPM: keep the FastCGI listener bound to 127.0.0.1:9000 (or a Unix socket) so only the local web server can reach it — never 0.0.0.0:9000. Patch PHP past the CVE-2019-11043 fix lines, and on nginx avoid the vulnerable fastcgi_split_path_info + PATH_INFO pattern with a try_files/file-existence check.
  • SonarQube: change the default admin password immediately, put the UI behind authenticated access and TLS on 443 via a reverse proxy, upgrade past the disclosed versions, and never expose /api/settings/values to untrusted networks.
  • Portainer: upgrade to 2.39.4 / 2.43.0 or later, and — critically — restrict network access before completing initial setup (firewall, security group, or reverse proxy) so no one reaches the unauthenticated init/restore window. Don’t leave a fresh instance internet-reachable.
  • ClickHouse / MinIO: set strong non-default credentials, disable anonymous/default-user access, and keep the native/API ports off the public internet.
  • Firewall port 9000 to only the hosts that legitimately need it, and audit cloud security groups and container port mappings for an accidental 0.0.0.0:9000.
  • Close it if nothing needs it, and rescan to confirm. An unexplained open 9000 is worth chasing down before you dismiss it as “a dev port.”

Real-World Example

The canonical port-9000 story is CVE-2019-11043, the PHP-FPM FastCGI underflow. It was discovered during Real World CTF 2019 when researcher Andrew Danau noticed that adding a %0a byte to a URL made an nginx + PHP-FPM server behave strangely; Omar Ganiev (neex) and Emil Lerner turned that observation into a reliable, remote, unauthenticated remote-code-execution exploit and released it as the phuip-fpizdam tool. The catch that makes it the perfect illustration of this port: the vulnerable component is PHP-FPM listening on 9000, but the exploit is delivered through the nginx front-end against a specific — and at the time extremely common — fastcgi_split_path_info configuration that shipped in default setups (Nextcloud’s recommended nginx config among them). Mass scanning for that config pattern let attackers pop servers without ever touching port 9000 directly. It’s the whole port-9000 lesson in one bug: the service on 9000 is where the flaw lives, but how it’s reachable — a localhost-only FastCGI socket versus one exposed to the network or fronted by a fragile proxy config — is what turns a defaulted dev port into remote code execution.

FAQ

What is port 9000 used for?

Port 9000 is a shared default with no single owner. Its most common occupants are PHP-FPM (the FastCGI Process Manager, bound to localhost by default), the SonarQube code-quality web UI, and the Portainer Docker management console. Data-infrastructure tools also default here: ClickHouse’s native protocol, MinIO’s S3 API/console, Hadoop’s HDFS fs.defaultFS, and Xdebug 2’s debugger port. On an open 9000, the first step is always to identify which of these is actually running.

Is it safe to expose PHP-FPM on port 9000?

No. FastCGI has no authentication, so any host that can reach PHP-FPM’s 9000 socket can send FastCGI requests that execute arbitrary PHP or read local files — no vulnerability needed, just network reachability. PHP-FPM should bind 127.0.0.1:9000 (or a Unix socket) and be spoken to only by the local web server. A 0.0.0.0:9000 FastCGI listener is effectively an unauthenticated remote shell.

How do I tell whether SonarQube, Portainer, or PHP-FPM is on port 9000?

Fingerprint it. curl -sI http://<host>:9000/ shows whether it answers as HTTP; curl -s http://<host>:9000/api/system/status returns SonarQube’s or Portainer’s status/version JSON. If the port is open but doesn’t respond to HTTP, probe it as FastCGI with cgi-fcgi -bind -connect <host>:9000 (a FastCGI reply means PHP-FPM), or try clickhouse-client --host <host> --port 9000 for a ClickHouse server.

Can port 9000 lead to remote code execution?

Yes, in two distinct ways. An exposed PHP-FPM FastCGI socket on 9000 allows direct PHP execution because FastCGI is unauthenticated. Separately, CVE-2019-11043 (CVSS 9.8) gives unauthenticated RCE against vulnerable nginx + PHP-FPM configurations, delivered through the web front-end. A hijacked Portainer instance (CVE-2026-55761) yields control of the container host, which is code execution by another route.

Is port 9000 TCP or UDP?

TCP. Every common port-9000 service — PHP-FPM’s FastCGI socket, SonarQube’s and Portainer’s HTTP APIs, ClickHouse’s native protocol, MinIO’s S3 API, and Xdebug’s DBGp listener — communicates over TCP.

How do I secure or close port 9000?

Identify the service first, then harden it: bind PHP-FPM to localhost and patch it, change SonarQube’s default credentials and put it behind authenticated TLS, upgrade Portainer and firewall it before setup, and set strong credentials on ClickHouse/MinIO. Firewall 9000 to only the hosts that need it, audit cloud security groups and container mappings for an accidental public bind, and if nothing legitimately uses the port, stop the service and confirm it’s closed with a rescan.

TL;DR

  • Service: no single owner — PHP-FPM (FastCGI) by default, plus SonarQube, Portainer, ClickHouse, MinIO, Hadoop HDFS, and Xdebug, among others
  • Default port: 9000/TCP (PHP-FPM 127.0.0.1:9000, SonarQube/Portainer/MinIO HTTP, ClickHouse native protocol)
  • Biggest risk: an exposed FastCGI socket = unauthenticated remote code execution (no CVE needed); plus SonarQube default creds/credential leak (CVE-2020-27986), Portainer admin takeover (CVE-2026-55761), and PHP-FPM RCE via nginx (CVE-2019-11043) — so fingerprint what’s answering before you trust it
  • Mitigation: identify the real service, keep PHP-FPM bound to localhost, change SonarQube defaults and add auth+TLS, patch and firewall Portainer before setup, lock down ClickHouse/MinIO credentials, and firewall or close port 9000 if nothing needs it — capture every finding in your pentest report