Severity: Moderate CVSS 3.1: AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N Affected: yamcs-core < 5.12.7 and < 5.13.0 Fixed in: 5.12.7 / 5.13.0 Advisory: GHSA-cqh3-jg8p-336j Reporter: Daniel Miranda Barcelona (Excal1bur) Discovery date: 2026-04-20

Context
If you’ve been following along, you already know YAMCS: the open-source mission control framework behind ESA’s OPS-SAT, various ground-station deployments, and a growing number of real space missions. We’ve been here before CVE-2026-44595 (user enumeration) and CVE-2026-44596 (no rate limiting) were the first two rounds. This is the third.
This one is different. The previous two were configuration and enforcement issues. This one is a classic injection bug sitting inside the authentication module itself and it targets deployments that integrate YAMCS with a corporate LDAP directory.
The vulnerability
YAMCS ships with a pluggable authentication system. One of the available backends is LdapAuthModule, which connects to an external LDAP server to validate user credentials. It’s configured via etc/security.yaml and widely used in enterprise deployments where users are managed centrally.
When a user authenticates, LdapAuthModule constructs an LDAP search filter to look up the account:
// VULNERABLE — LdapAuthModule.java:233
var filter = userFilter.replace("{0}", username);
var searchResult = getSingleResult(ctx, userBase, filter, controls);The username value comes directly from the authentication request and is dropped into the filter string with no escaping whatsoever. LDAP filter syntax (defined in RFC 4515) reserves several special characters: *, (, ), \, and the null byte. None of them are sanitized here.
The consequence: an attacker can craft a username that manipulates the LDAP search filter and changes who the query matches.
Impact
The most straightforward attack: authenticate as an arbitrary user without knowing their password.
Send username=* with any valid password. The wildcard expands the filter to match all users in the directory, and the search returns the first result whoever that happens to be. If the attacker knows one valid credential (even their own account’s password), they can potentially authenticate as any other user the LDAP search returns first.
curl -X POST "http://TARGET:8090/auth/token" \
-d "grant_type=password&username=*&password=known_password"
# Returns a token for the first LDAP user returned by the wildcard searchThis is horizontal privilege escalation: one known credential can give you access to a different account. The severity is Moderate rather than High because:
- It requires
PR:L(at least one valid credential to supply the password field). - Confidentiality impact is
Lowyou’re accessing another user’s session, not extracting the LDAP directory itself. - No integrity or availability impact in the base score.
That said, in a mission-operations context where YAMCS operators have privileged access to spacecraft commanding interfaces, impersonating another operator is not a small thing.
Root cause
One line. No RFC 4515 escaping before the filter is constructed:
// VULNERABLE
var filter = userFilter.replace("{0}", username);This is a textbook injection: user-controlled input concatenated directly into a structured query language without sanitisation. The LDAP equivalent of SQL injection not novel, but easy to miss when you’re focused on what the filter does rather than what it accepts.
Notably, the LDAP wildcard * is the most obvious exploit vector, but ( and ) can also be used to break and rewrite filter logic entirely, enabling more targeted attacks depending on the filter template in use.
Fix
Applied in yamcs-core 5.12.7 and 5.13.0: escape the username against RFC 4515 before it touches the filter string.
private static String escapeLdapFilter(String input) {
return input
.replace("\\", "\\5c")
.replace("*", "\\2a")
.replace("(", "\\28")
.replace(")", "\\29")
.replace("\0", "\\00");
}
// FIXED
var filter = userFilter.replace("{0}", escapeLdapFilter(username));Backslash first (to avoid double-escaping), then the four other reserved characters. The fix is minimal, correct, and follows the RFC to the letter. Once escaped, a wildcard in the username is treated as a literal * character, not a filter operator.
If you’re on an affected version and can’t upgrade immediately: restrict access to the YAMCS auth endpoint at the network layer, or switch to a different auth backend until you can patch.
