Skip to content

CVE-2026-63077: Verified Reproduction

CVE-2026-63077: JetBrains TeamCity On-Premises unauthenticated RCE via agent polling protocol

CVE-2026-63077 is verified against the affected target. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00329.

REPRO-2026-00329 RCE Aug 23, 2026 CVE entry .txt
Severity
CRITICAL
Confidence
HIGH
Reproduced in
100m 55s
Tool calls
347
Spend
$11.40
01 · Overview

What Is CVE-2026-63077?

CVE-2026-63077 is a critical-severity RCE vulnerability. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00329).

02 · Severity & CVSS

CVE-2026-63077 Severity

CVE-2026-63077 is rated critical severity.

CRITICAL threat level
Weakness CWE-502 (Deserialization of Untrusted Data) — Deserialization of Untrusted Data

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

How to Reproduce CVE-2026-63077

$ pruva-verify REPRO-2026-00329
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00329/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-63077

Remote code execution — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

HTTP bodies of POST /app/agents/v1/register (agentDetails XML) and POST /app/agents/v1/commands/error (XStream gadget XML), plus TeamCity-AgentSessionId/TeamCity-AgentCommandId headers

Attack chain
  1. POST /app/agents/v1/register (unauthenticated session issuance)
  2. POST /app/agents/v1/commands/error
  3. Error.fromXml
  4. unrestricted XStream deserialization
  5. HSQLMetadataStorage$SchemaMismatchException/BasicDataSource/HashAdapter/TiedMapEntry gadget
  6. HSQLDB SCRIPT drops .jspws webshell
  7. GET /<rand>.jspws
  8. Runtime.exec as tcuser
Runnable proof: reproduction_steps.sh
Captured evidence: teamcity fixed server
How the agent worked 761 events · 347 tool calls · 1h 41m
1h 41mDuration
347Tool calls
143Reasoning steps
761Events
21Dead-ends
Agent activity over 1h 41m
Policy
1
Support
12
Repro
454
Judge
39
Variant
250
Verify
1
0:00100:40

Root Cause and Exploit Chain for CVE-2026-63077

Versions: all TeamCity On-Premises versions before 2025.11.7 / 2026.1.3

JetBrains TeamCity On-Premises is vulnerable to unauthenticated remote code execution (CWE-502, deserialization of untrusted data) in its agent polling protocol. The server-side handler jetbrains.buildServer.agentServer.polling.Error.fromXml() (and the sibling XStreamHolders in PollingRemoteAgentConnection, RunBuildCommandResult, and NodesAwareLogMessagePersister) deserializes attacker-controlled HTTP request bodies with an XStream instance configured with AnyTypePermission.ANY and only a small denylist. An unauthenticated attacker first registers a synthetic build agent via POST /app/agents/v1/register (which issues a valid TeamCity-AgentSessionId without any credentials), then posts a crafted XStream XML document to POST /app/agents/v1/commands/error. The embedded gadget chain starts an HSQLDB connection whose connectionInitSqls drop a self-deleting .jspws webshell into the TeamCity webroot; a single GET to that file executes an arbitrary OS command with the privileges of the TeamCity server process.

  • Package/component: JetBrains TeamCity On-Premises server (webapps/ROOT webapp, classes in server-core.jar, common-impl.jar, messages.jar, web-core.jar).
  • Affected versions: all TeamCity On-Premises versions before 2025.11.7 / 2026.1.3 (verified vulnerable: 2025.11.6, build 208214; verified fixed: 2025.11.7).
  • Risk: CVSS 3.1 9.8 Critical (AV:N/AC:L/PR:N/UI:N). Listed in CISA KEV (added 2026-08-05) with confirmed in-the-wild exploitation. Full server compromise: arbitrary OS command execution as the TeamCity server user, access to build secrets, source code, CI/CD pipeline integrity.

Impact Parity

  • Disclosed/claimed maximum impact: unauthenticated remote code execution.
  • Reproduced impact from this run: unauthenticated remote OS command execution (touch <marker> executed as tcuser, the TeamCity server process user, inside the official jetbrains/teamcity-server:2025.11.6-linux container), proven by the command-created marker file and by the one-shot JSPWS response token.
  • Parity: full.
  • Not demonstrated: nothing material — the claim is unauthenticated RCE and exactly that was demonstrated, twice, through the real HTTP surface.

Root Cause

The agent polling protocol is served by jetbrains.buildServer.controllers.agentServer.AgentPollingProtocolController (web-core.jar), reachable under /app/agents/v1/... with no servlet-level authentication: agent identity is established only by the TeamCity-AgentSessionId header (<agentId>:<authorizationToken>), and a fresh valid session is handed out by the unauthenticated register action to any caller (createRegisteredAgentWithPollingConnectionregisterAgent → session id in the TeamCity-AgentSessionId response header).

For the commands/error sub-path, AbstractAgentCommandsRequestsProcessor. handleCommandIsFailedRequest executes:

Error error = Error.fromXml(StreamUtil.readTextFrom(request.getReader()));  // <- sink
int n = Integer.parseInt(request.getHeader("TeamCity-AgentCommandId"));

Error.fromXmlXStreamWrapper.deserializeObject(xml, ourXStreamHolder). jetbrains.buildServer.messages.XStreamHolder (messages.jar) configures its XStream as:

xstream.addPermission(AnyTypePermission.ANY);
xstream.denyTypes(new String[]{ "java.beans.EventHandler", "java.lang.ProcessBuilder",
    "javax.imageio.ImageIO$ContainsFilter", "jdk.nashorn.internal.objects.NativeString",
    "com.sun.corba.se.impl.activation.ServerTableEntry",
    "com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator",
    "sun.awt.datatransfer.DataTransferer$IndexOrderComparator", "sun.swing.SwingLazyValue"});
xstream.denyTypesByRegExp(/* LazyIterator, LazyEnumeration, GetterSetterReflection,
    PrivilegedGetter, java.rmi, javax.crypto, ServiceNameIterator, JavaFX, BCEL */);

i.e. an "allow everything except a 2016-era blacklist" configuration. Bundled libraries (commons-collections 3.2.2, freemarker 2.3.31, commons-dbcp2/pool2, hsqldb, plus TeamCity's own classes) provide all the gadget classes needed for code execution.

The exploit gadget chain (identical to the in-the-wild chain captured by honeypots and documented by Rapid7):

  1. linked-hash-map entry value typed as TeamCity's own jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage$SchemaMismatchException (a Throwable, so it passes XStream 1.4.20's default hierarchy permission). Its declared fields instantiate HSQLStorage with a DBCP2 BasicDataSource whose driverClassName=org.hsqldb.jdbc.JDBCDriver, url=jdbc:hsqldb:mem:<rand>, and three attacker-controlled connectionInitSqls.
  2. A freemarker.ext.beans.HashAdapter whose falseModel.object is an XStream reference= to that BasicDataSource, giving a Map view whose get("connection") invokes BasicDataSource.getConnection() via FreeMarker bean introspection.
  3. A set containing org.apache.commons.collections.keyvalue.TiedMapEntry (not covered by commons-collections 3.2.2's readObject serialization guard) bound to that map with key "connection". During HashSet population, TiedMapEntry.hashCode()getValue()map.get("connection")BasicDataSource.getConnection() → DBCP runs the three init SQL statements against the in-memory HSQLDB: CREATE TABLE, INSERT '<JSP scriptlet>', and SCRIPT '../webapps/ROOT/<rand>.jspws', which writes a polyglot SQL/JSP webshell into the TeamCity webroot.
  4. GET /<rand>.jspws compiles and runs the scriptlet, which deletes itself and calls java.lang.Runtime.getRuntime().exec(<attacker command>), printing a per-run token.

Fix (confirmed by decompiling the official fix_CVE_2026_63077.zip security patch plugin, build limit max-build="222648"): the patch reflectively replaces every XStreamHolder used by the polling protocol (PollingRemoteAgentConnection.myXStreamHolder, Error.xStreamHolder, RunBuildCommandResult.ourXStreamHolder, NodesAwareLogMessagePersister.xStreamHolder) with a wrapper whose getXStream() adds NoTypePermission.NONE plus an explicit allowlist of ~100 jetbrains.buildServer.* data classes. It also installs an AddToQueuePreprocessor that strips queued builds carrying the teamcity.agent.internal.passwords.values parameter. Fixed releases 2025.11.7 / 2026.1.3 ship the same allowlist natively.

Reproduction Steps

  1. bundle/repro/reproduction_steps.sh (self-contained; requires docker, python3, curl).
  2. The script:
    • pulls the pinned official images jetbrains/teamcity-server@sha256:a435d8…4176 (2025.11.6, vulnerable) and …@sha256:d3875b…56d8 (2025.11.7, fixed);
    • starts both servers and drives the real first-run setup wizard over HTTP (/mnt/do/goNewInstallation/mnt/do/goNewDatabase (internal HSQLDB) → /mnt/do/acceptLicenseAgreement) until the server leaves maintenance mode;
    • health-checks the attack surface by registering an agent without credentials and verifying a TeamCity-AgentSessionId header is issued;
    • runs the exploit (bundle/repro/exploit_cve_2026_63077.py, vendored Rapid7 PoC) twice against the vulnerable server and twice against the fixed server, with per-run random markers;
    • requires, on the vulnerable server: exploit exit 0 and the marker file present inside the container (created by the TeamCity server process);
    • requires, on the fixed server: exploit failure, no marker file, and com.thoughtworks.xstream.security.ForbiddenClassException in the server log (the exact IoC JetBrains names for a blocked exploit attempt).
  3. Expected evidence: [+] Command executed: touch /tmp/CVE_2026_63077_PWNED_<rand> for 2025.11.6, HTTP 404 for the webshell on 2025.11.7, and RESULT: … CONFIRMED.

Evidence

  • bundle/logs/reproduction_steps.log — full orchestration log.
  • bundle/logs/exploit_vulnerable.log — two successful exploit runs: register → TeamCity-AgentSessionId: <id>:<token>/app/agents/v1/commands/error HTTP 500 (deserialization side effects already committed) → GET /<rand>.jspws HTTP 200 with the per-run response token.
  • bundle/repro/marker_vulnerable.txtls -la of the marker file (owner tcuser) and id of the server process user inside the container.
  • bundle/logs/teamcity_vuln_server.log — vulnerable server log containing the com.thoughtworks.xstream.converters.ConversionException IoC named in JetBrains' guidance.
  • bundle/logs/exploit_fixed.log, bundle/logs/teamcity_fixed_server.log — fixed server: same requests, ForbiddenClassException ×2, webshell GET → HTTP 404, no marker.
  • bundle/repro/payload_vulnerable.xml — the exact attack XML generated for the run.
  • bundle/repro/analysis/ — patch-diff evidence: decompiled JetBrains security patch plugin classes, decoded allowlist, decompiled Error/AgentPollingProtocolController/ AbstractAgentCommandsRequestsProcessor/XStreamHolder from 2025.11.6, and the in-the-wild honeypot pcap (CVE-2026-63077-itw.pcap, BoredHackerBlog) showing the identical request sequence.
  • Environment: official Docker images on linux/amd64; TeamCity 2025.11.6 (build 208214) with bundled Tomcat 9.0.109 / JetBrains Runtime 21; no sanitizer, no instrumentation.

Recommendations / Next Steps

  • Upgrade to TeamCity 2025.11.7 or 2026.1.3, or install JetBrains' fix_CVE_2026_63077 security patch plugin (2017.1+; restart required on 2017.1–2018.1).
  • Restrict network access to the server (the agent polling protocol is same-port HTTP(S)) to trusted build-agent networks.
  • Detection: server logs containing ConversionException (possible attempt/success) or ForbiddenClassException (blocked attempt on patched servers); unexpected unauthorized agents (in-the-wild agents used names starting with scan); unexpected .jspws/.jsp files under webapps/ROOT.
  • The correct fix pattern is exactly what JetBrains shipped: never deserialize the polling protocol with AnyTypePermission.ANY; use NoTypePermission.NONE + a strict allowlist.

Additional Notes

  • Idempotency: the script recreates both containers from pinned image digests on every run and uses fresh random markers/tokens, so consecutive runs are independent.
  • The exploit does not depend on the TeamCity-AgentCommandId value (deserialization happens before the header is parsed); any integer suffices.
  • On the vulnerable server the /commands/error request returns HTTP 500 after the gadget side effects have executed — the 500 is expected and matches the in-the-wild capture.
  • Exploit helper provenance: bundle/repro/exploit_cve_2026_63077.py is the public Rapid7 PoC (github.com/sfewer-r7/CVE-2026-63077), used unmodified; the same chain was independently captured in the wild (pcap in bundle/repro/analysis/).
  • The default --webroot-relative ../webapps/ROOT is correct for the official Linux Docker image (JVM working directory /opt/teamcity/bin).

CVE-2026-63077 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:002:33
0:00
session startedaccounts/fireworks/models/kimi-k3 · CVE-2026-63077 · REPRO-20
0:06
0:22
web search
0:32
0:37
0:38
web search
1:12
1:12
extract_facts
no facts extracted
1:14
1:14
supportclaim_contract
1:23
1:23
1:23
1:28
1:28
1:28
1:28
1:35
1:35
1:49
1:49
1:51
web search
1:51
$which docker; docker --version 2>/dev/null; java -version 2>&1 | head -3; python3 --version; df -h /workspace /tmp | tail -3; ls /pruva/project-cache 2>/dev/null
0.7s
/usr/bin/docker
Docker version 29.1.3, build 29.1.3-0ubuntu4.1
pruva-command: 1: java: not found
Python 3.14.4
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           2.4G   36K  2.3G   1% /workspace
overlay         145G   33G  112G  23% /
repo-mirrors
2:07
2:08
2:10
web search
2:27
2:32
$curl -s "https://hub.docker.com/v2/repositories/jetbrains/teamcity-server/tags/?name=2025.11&page_size=25" | jq -r '.results[].name' 2>/dev/null; echo ---; curl -s "https://hub.docker.com/v2/repositories/jetbrains/teamcity-server/tags/?name=2026.1&page_size=25" | jq -r '.results[].name' 2>/dev/null
5.1s
2025.11.7
2025.11.7-nanoserver-2022
2025.11.7-nanoserver-1809
2025.11.7-linux-arm64
2025.11.7-linux
2025.11.6
2025.11.6-nanoserver-1809
2025.11.6-nanoserver-2022
2:33
$curl -sI https://download.jetbrains.com/teamcity/TeamCity-2025.11.6.tar.gz | head -8; echo ---; curl -sI https://download.jetbrains.com/teamcity/TeamCity-2025.11.7.tar.gz | head -8
0.7s
HTTP/2 302 
content-type: text/html
content-length: 138
location: https://download-cdn.jetbrains.com/teamcity/TeamCity-2025.11.6.tar.gz
date: Sun, 23 Aug 2026 06:16:30 GMT
x-geocode: NL
server: nginx
strict-transport-security: max-age=31536000; includeSubdomains;
08 · How to Fix

How to Fix CVE-2026-63077

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-63077 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-63077

Is CVE-2026-63077 exploitable?

Yes. Pruva independently reproduced CVE-2026-63077 and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00329).

How severe is CVE-2026-63077?

CVE-2026-63077 is rated critical severity.

What type of vulnerability is CVE-2026-63077?

CVE-2026-63077 is classified as CWE-502 (Deserialization of Untrusted Data) (Deserialization of Untrusted Data), a RCE vulnerability.

How can I reproduce CVE-2026-63077?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the CVE-2026-63077 reproduction verified?

Yes. Pruva reproduced CVE-2026-63077 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for CVE-2026-63077

Authoritative sources for CVE-2026-63077 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.