The Tomcat Manager and Host Manager web applications are administrative interfaces bundled with standalone Tomcat distributions. The Manager app deploys and undeploys WAR files, lists and invalidates HTTP sessions, reloads applications, and exposes server status. The deploy capability is a direct path to remote code execution: an attacker uploads a WAR containing a webshell or reverse-shell payload, Tomcat auto-deploys it, and the code runs inside the JVM with the filesystem and network access of the Tomcat process.
A default standalone Tomcat install ships the Manager app under webapps/, but conf/tomcat-users.xml ships with no users assigned manager roles. The app exists but is inaccessible until an administrator configures a user. The problem begins when someone adds a user with weak or default credentials and leaves the Manager endpoint reachable beyond localhost. Automated scanners test these credential pairs constantly. A single successful login becomes full server compromise.
This article covers the attack surface, how to audit whether your instance is exposed, how to detect compromise from access logs, and how to lock down or remove the Manager app in production.
What the Manager app exposes
The Manager (/manager) and Host Manager (/host-manager) applications are privileged webapps deployed by default in standalone Tomcat under $CATALINA_BASE/webapps/manager/ and $CATALINA_BASE/webapps/host-manager/.
Manager roles control what an authenticated user can do:
| Role | Endpoint | Capability |
|---|---|---|
manager-gui | /manager/html | HTML interface: deploy, undeploy, reload, list sessions |
manager-script | /manager/text/* | Script-friendly text interface: deploy and undeploy via HTTP commands |
manager-jmx | /manager/jmxproxy/* | JMX proxy: read and invoke JMX MBeans |
manager-status | /manager/status | Server status page only |
The Host Manager app (/host-manager/html) has its own roles: admin-gui and admin-script. These are separate from the manager roles.
The critical capability is WAR deployment. A user with manager-gui or manager-script can upload a WAR file. Tomcat unpacks it and the application runs immediately with the JVM’s permissions. A WAR containing a JSP webshell gives the attacker arbitrary command execution on the host.
The manager-script role is more dangerous than manager-gui because the text interface at /manager/text/ is scriptable. An attacker does not need a browser session. curl commands suffice to deploy and undeploy applications, making automation trivial.
Embedded Tomcat distributions (Spring Boot) do not include the Manager or Host Manager applications. This attack surface exists only in standalone Tomcat deployments.
How the attack chain works
The compromise follows a predictable path:
flowchart TD
A["Manager reachable from
non-localhost source"] --> B["Scanner tests
default credential pairs"]
B --> C{"Valid credentials
in tomcat-users.xml?"}
C -->|Yes| D["Attacker authenticated
to /manager/html"]
C -->|No| E["Sustained 401 noise
no compromise yet"]
D --> F["Upload malicious WAR
via /manager/text/deploy"]
F --> G["Tomcat auto-deploys
WAR with JVM privileges"]
G --> H["Webshell or reverse shell
= remote code execution"]
H --> I["Persistence and
lateral movement"]Each step has a detectable signal. The operational question is whether your monitoring captures them before step H.
The chain requires two preconditions.
Reachability. The Manager endpoint must accept connections from beyond localhost. Tomcat’s default context.xml for the Manager app includes a RemoteAddrValve that restricts access to 127.x.x.x and ::1. If someone removes or weakens that valve, or deploys behind a reverse proxy that forwards requests to the Manager path, the endpoint becomes reachable from the network.
Valid credentials. The default tomcat-users.xml ships with no users assigned any manager role. The vulnerability appears when an operator adds a user with a weak password. Commonly tested credential pairs are admin:admin, tomcat:tomcat, manager:manager, tomcat:s3cret, admin:password, and both:tomcat. Automated scanners cycle through these within minutes of discovering an open /manager/html.
Detecting exposure and compromise
Check whether Manager is deployed
# Check if Manager and Host Manager are present
ls "$CATALINA_BASE/webapps/manager/" 2>/dev/null && echo "MANAGER DEPLOYED" || echo "MANAGER ABSENT"
ls "$CATALINA_BASE/webapps/host-manager/" 2>/dev/null && echo "HOST MANAGER DEPLOYED" || echo "HOST MANAGER ABSENT"
In production, both should ideally be absent. If they exist and you do not actively use them for deployment, remove them.
Check the access restriction valve
# Inspect the Manager context.xml for the RemoteAddrValve
grep -iE "RemoteAddr|RemoteCIDR|allow" "$CATALINA_BASE/webapps/manager/META-INF/context.xml"
The default restricts access to localhost. If the valve is missing, commented out, or the allow pattern includes broad ranges, the Manager is reachable from the network and is an active attack surface.
Check for weak credentials
# Look for users assigned manager or admin roles
grep -E 'roles="[^"]*(manager|admin)' "$CATALINA_BASE/conf/tomcat-users.xml"
# Check for usernames matching common defaults
grep -E 'username=.*(tomcat|admin|manager|root|both)' "$CATALINA_BASE/conf/tomcat-users.xml"
Any user with a manager role should have a strong, unique password. If a password matches the username or a well-known default string, treat the instance as potentially compromised.
Test reachability from an external source
# From a host OUTSIDE the trusted network. Run only against systems you own.
curl -s -o /dev/null -w "%{http_code}\n" http://<external-ip>:8080/manager/html
Interpret the response code:
- 403 = access restricted by the valve. Good.
- 401 = Manager is reachable and requires authentication. Bad: the attack surface is exposed to brute force.
- 200 = Manager fully accessible. Critical: immediate compromise risk.
Detect compromise from access logs
A successful 200 response to /manager/html or /manager/text/* from an unexpected source IP is a binary compromise signal. Check the access log immediately:
# Default access log format: %h %l %u %t "%r" %s %b
# The request path is INSIDE the quoted request line, BEFORE the status code.
LOG="$CATALINA_BASE/logs/localhost_access_log.$(date +%Y-%m-%d).txt"
# Find successful Manager access from non-localhost sources
grep -E '/manager/[^"]*" 200 ' "$LOG" | \
awk '$1 !~ /^(127\.|::1|10\.|192\.168\.|172\.)/ {print}'
# Check for WAR deployment via Manager API
grep -E '(POST|PUT).*/manager/(text/deploy|html/upload)' "$LOG"
The awk filter excludes all 172.* addresses, which is broader than RFC1918’s 172.16.0.0/12. Acceptable for triage; tighten if you legitimately serve traffic from the 172.0.0.0/8 public ranges.
If you find a successful deployment request from an unexpected source, the instance is likely compromised. Check for unauthorized WAR files:
# List WAR files with modification times
ls -la "$CATALINA_BASE/webapps/"*.war
# Find recently modified files in webapps (last 24 hours)
find "$CATALINA_BASE/webapps/" -mmin -1440 -type f
Also check catalina.out for deployment events:
grep "org.apache.catalina.startup.HostConfig.deployWAR" "$CATALINA_BASE/logs/catalina.out"
Any deployment event outside a planned maintenance window requires investigation. Tomcat’s autoDeploy defaults to true, so a WAR file placed in webapps/ is deployed automatically without any Manager interaction. An attacker with filesystem write access does not need Manager credentials to achieve RCE.
Locking it down
Option 1: Remove the Manager app entirely
If you do not use the Manager app for routine deployments, remove it. This is the only option that eliminates the attack surface completely.
# Destructive: remove Manager and Host Manager webapps
rm -rf "$CATALINA_BASE/webapps/manager"
rm -rf "$CATALINA_BASE/webapps/host-manager"
Tomcat’s autoDeploy picks up the removal on the next scan. In containerized deployments, build the image without these directories from the start.
Option 2: Restrict access to localhost or a management network
If you need the Manager app for operational tasks, restrict it at the network layer. The default context.xml for the Manager app includes a RemoteAddrValve that limits access to loopback addresses:
<Context privileged="true">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
</Context>
To allow access from a VPN or management subnet, add those CIDR ranges to the allow attribute. Do not broaden it to include public address space.
If the Manager app sits behind a reverse proxy, block /manager/* and /host-manager/* paths at the proxy level. Do not rely solely on Tomcat’s valve if the proxy forwards all paths indiscriminately.
Option 3: Strengthen credentials and verify LockOutRealm
If the Manager app must remain accessible, enforce strong authentication.
Tomcat’s server.xml can wrap the UserDatabaseRealm in a LockOutRealm, which locks out a user account after a configurable number of failed authentication attempts. Check whether it is present:
grep -i "LockOutRealm" "$CATALINA_BASE/conf/server.xml"
Ensure all users with manager roles have strong, unique passwords. Rotate any password that matches a known default pattern. Audit tomcat-users.xml for stale accounts and remove any that are no longer needed.
Monitoring for Manager access
The access log is the primary detection surface. Conditions requiring attention:
| Signal | Why it matters | Warning sign |
|---|---|---|
401/403 rate to /manager/* | Brute-force or credential stuffing in progress | Sustained rate from a single source IP or distributed sources |
200 to /manager/html from unexpected IP | Successful unauthorized access: potential compromise | Any 200 from a source outside your known admin network |
POST/PUT to /manager/text/deploy | WAR deployment via Manager API | Any deployment outside a planned maintenance window |
New WAR file in webapps/ | Persistence mechanism after compromise | Any unexpected file, especially outside deploy windows |
deployWAR in catalina.out | Tomcat logged a WAR deployment event | Correlate with deployment schedule; investigate unscheduled events |
The page-worthy signal is a 200 to /manager/html from an unexpected source. This is not a rate-based alert. It is a binary security event. If your access log monitoring can alert on this pattern, enable it.
The ticket-worthy signal is sustained 401/403 responses to /manager/* from concentrated source IPs. This indicates brute-force attempts. On internet-facing servers, individual failed attempts are too noisy to alert on individually. Use a rate threshold, for example more than 10 per minute from a single source.
How Netdata helps
- Access log parsing can surface
200responses to/manager/*and/host-manager/*paths as discrete security events, correlating the source IP against known admin networks. - Per-second metric collection means a burst of 401 responses to Manager endpoints is visible immediately, not minutes later in a batched log scan.
- Anomaly detection on request rate and error rate helps distinguish routine 404 noise from a concentrated brute-force pattern directed at
/manager/html. - Correlation between deployment events (new files in
webapps/,deployWARlog lines) and access log patterns helps reconstruct the compromise timeline during incident response. - Process and connector metrics confirm whether Tomcat is still serving traffic after a suspected compromise, and whether an unauthorized deployment caused resource anomalies such as unexpected CPU, memory, or thread count changes.
Related guides
- Tomcat 5xx error rate: separating server failures from crawler 404s
- Tomcat accept queue overflow: acceptCount, somaxconn, and Recv-Q
- Tomcat access log setup: adding %D and %T for per-request latency
- Tomcat java.net.BindException: Address already in use: the connector never starts
- Tomcat average latency lies: why you need p95/p99 from the access log
- Tomcat threads blocked forever: the missing outbound timeout
- Tomcat classloader leak on redeploy: why the old WebappClassLoader never dies
- Tomcat connection refused: maxConnections and acceptCount both exhausted
- Tomcat accepts connections but never responds: the TCP-connect trap
- Tomcat file descriptor usage: OpenFileDescriptorCount vs the ulimit
- Tomcat frequent Full GC: pause time, G1, and the 5% overhead rule
- Tomcat GC death spiral: full GCs dominating and throughput collapsing






