LDAP Signing and Channel Binding: How to Enforce Secure LDAP on Domain Controllers Without Breaking AD-Integrated Applications

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
Unsigned LDAP allows a man-in-the-middle attacker to modify directory queries and responses in transit, manipulate authentication outcomes, and replay authentication tokens. Despite this, unsigned LDAP has been the default on Windows domain controllers for decades because enforcing signing breaks older applications. The audit-first approach resolves this: generate Event ID 2889 for 30 days to identify every client making unsigned LDAP binds, then remediate those clients or accept the loss of their LDAP functionality before enabling enforcement.
Enabling the LDAP Diagnostic Event Log to Find Unsigned Binders
The LDAP diagnostic event log is disabled by default. Enable it on domain controllers to generate Event ID 2889 for every unsigned LDAP bind:
# Enable LDAP diagnostics for unsigned bind detection on all DCs
$DCs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
foreach ($DC in $DCs) {
Invoke-Command -ComputerName $DC -ScriptBlock {
# Set LDAP Interface Events diagnostic level to 2 (verbose) for signing detection
$ldapDiagPath = "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics"
Set-ItemProperty -Path $ldapDiagPath -Name "16 LDAP Interface Events" -Value 2
Write-Output "LDAP diagnostics enabled on $env:COMPUTERNAME"
}
}
After enabling, unsigned LDAP bind attempts generate Event ID 2889 in the Directory Services event log on the DC that processed the bind. The event contains:
- The client's IP address
- The distinguished name (DN) of the account used for the bind
- The LDAP bind type (Simple / SASL without signing)
Collect Event 2889 from all DCs over 30 days:
# Collect Event 2889 across all DCs
$results = foreach ($DC in $DCs) {
Get-WinEvent -ComputerName $DC -FilterHashtable @{
LogName = 'Directory Service'
Id = 2889
StartTime = (Get-Date).AddDays(-30)
} -ErrorAction SilentlyContinue | ForEach-Object {
$xml = [xml]$_.ToXml()
[PSCustomObject]@{
DC = $DC
Time = $_.TimeCreated
ClientIP = $xml.Event.EventData.Data[0].'#text'
Account = $xml.Event.EventData.Data[1].'#text'
BindType = $xml.Event.EventData.Data[2].'#text'
}
}
}
$results | Export-Csv -Path "unsigned_ldap_binders.csv" -NoTypeInformation
Identifying and Categorizing Unsigned LDAP Sources
After collecting 2889 events, group the client IPs into categories to prioritize remediation:
# Summarize unsigned LDAP sources by client IP and account
Import-Csv -Path "unsigned_ldap_binders.csv" |
Group-Object ClientIP |
Select-Object @{N='ClientIP';E={$_.Name}},
@{N='EventCount';E={$_.Count}},
@{N='Accounts';E={($_.Group.Account | Sort-Object -Unique) -join '; '}} |
Sort-Object EventCount -Descending |
Format-Table -AutoSize
Common unsigned LDAP source categories:
Network devices (switches, printers, firewalls): These use LDAP for authentication (802.1X, LDAP-based login). Most cannot be upgraded to support signing. Solution: migrate these to LDAPS (port 636) with a valid DC certificate, or use a separate read-only DC for LDAP authentication from legacy devices with a limited credential scope.
Monitoring and backup systems: SNMP-based monitoring tools, backup agents, and ITSM integrations often use LDAP for user lookups. Most modern versions support LDAPS. Update to the current version and configure the LDAPS endpoint.
Legacy applications: On-premises applications with hardcoded LDAP endpoints. Solution: configure the application to use LDAPS (port 636) with certificate validation, or move authentication to SAML/OIDC via ADFS/Entra ID.
Automation scripts: PowerShell or Python scripts using the DirectorySearcher or ldap3 library with unsigned binds. Update the script to use LDAPS or SASL signing.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Configuring LDAPS on Domain Controllers
LDAPS requires each DC to have a valid server certificate. In environments with an internal PKI, deploy certificates automatically via autoenrollment:
# Verify DCs have certificates with Server Authentication OID (1.3.6.1.5.5.7.3.1)
foreach ($DC in $DCs) {
$cert = Invoke-Command -ComputerName $DC -ScriptBlock {
Get-ChildItem Cert:\LocalMachine\My |
Where-Object { $_.EnhancedKeyUsageList.ObjectId -contains '1.3.6.1.5.5.7.3.1' } |
Select-Object Subject, NotAfter, Thumbprint | Select-Object -First 1
}
Write-Output "$DC - Certificate: $($cert.Subject), Expires: $($cert.NotAfter)"
}
If DCs do not have suitable certificates:
- Create a certificate template for Kerberos Authentication or Domain Controller Authentication in your CA
- Configure autoenrollment via GPO: Computer Configuration > Windows Settings > Security Settings > Public Key Policies > Certificate Services Client - Auto-Enrollment
- Force enrollment:
certutil -pulseorgpupdate /force
Verify LDAPS is functional after certificate deployment:
# Test LDAPS connectivity from a client (Linux)
ldapsearch -H ldaps://dc01.domain.com -x -b "DC=domain,DC=com" -D "svc-ldap@domain.com" -W "(objectClass=domain)" -LLL
# Test from Windows
ldp.exe # Connect to DC on port 636 using SSL
Enabling LDAP Signing and Channel Binding via GPO
After remediating or documenting all unsigned LDAP clients, enable signing and channel binding on domain controllers:
LDAP Signing Policy (Domain Controller-side requirement):
GPO: Default Domain Controllers Policy (or a DC-specific GPO)
Path: Computer Configuration > Windows Settings > Security Settings > Local Policies > Security Options
Setting: Domain controller: LDAP server signing requirements
Value: Require signing
LDAP Channel Binding (requires Windows Server 2019 or later with the March 2020 patch):
Path: Computer Configuration > Windows Settings > Security Settings > Local Policies > Security Options
Setting: Domain controller: LDAP server channel binding token requirements
Value: Always (most secure) or When supported
Set to When supported initially, which only enforces channel binding for clients that advertise channel binding support. Move to Always after confirming all clients are compatible.
Client-side setting (enforce on all domain-joined clients as well):
GPO: Default Domain Policy or workstation/server OU GPO
Path: Computer Configuration > Windows Settings > Security Settings > Local Policies > Security Options
Setting: Network security: LDAP client signing requirements
Value: Require signing
Deploy in this sequence:
- Enable DC diagnostic (Event 2889) and collect for 30 days
- Remediate unsigned LDAP clients
- Set DC signing requirement to
Negotiate signing(allows signed or unsigned, but logs violations) - Monitor for new Event 2889 events
- After 2 weeks of zero 2889 events, set DC signing requirement to
Require signing
Common Application Compatibility Breaks After Enforcement
Despite thorough pre-enforcement auditing, some applications surface only after enforcement because they perform LDAP binds infrequently (password reset workflows, quarterly report generation, emergency access scenarios).
Diagnosing post-enforcement breaks: When an application fails after LDAP signing enforcement, check:
- The application's error log for LDAP authentication errors (LDAP error code 52 = Unavailable, 49 = Invalid credentials after signing failure)
- The DC Directory Services event log for Event 2889 (if any remain after enabling enforcement, the diagnostic level must be rechecked)
- Network capture from the application server to verify whether it is connecting to port 389 (unsigned) or 636 (LDAPS)
Common break scenarios and fixes:
| Application Type | Break Cause | Fix |
|---|---|---|
| Cisco ISE, Aruba ClearPass | LDAP auth on port 389 | Configure LDAPS endpoint |
| Splunk LDAP auth | Signing negotiation failure | Upgrade to current Splunk; enable SSL in LDAP settings |
| VMware vCenter | Simple bind on port 389 | Configure identity source to use LDAPS |
| Legacy IBM/Oracle apps | Hardcoded DirectorySearcher | Update app config to LDAPS or abstract via ADFS SAML |
| Ansible playbooks | ldap3 library without TLS | Add use_ssl=True, use_server_side_sasl=False to ldap3 connection |
The bottom line
LDAP signing and channel binding enforcement is a meaningful security control that requires audit-before-enforcement discipline. Enable Event ID 2889 on all domain controllers for 30 days before touching any signing GPO. Collect, categorize, and remediate all unsigned LDAP clients. Migrate devices and applications to LDAPS (port 636) wherever possible. Deploy the DC signing requirement in stages: Negotiate, then Require, with monitoring between stages. The process is operationally complex but closes a man-in-the-middle attack surface that has been exploited in real-world domain compromise scenarios.
Frequently asked questions
Does LDAP signing protect against NTLM relay attacks?
Partially. LDAP signing prevents tampering with LDAP requests in transit and prevents simple LDAP relay (where an attacker relays an unsigned LDAP authentication to a DC). However, NTLM relay attacks that relay authentication to LDAP specifically target unsigned LDAP. Enabling LDAP signing eliminates this relay attack vector. For comprehensive NTLM relay protection, also disable NTLM where possible, enable SMB signing, enable Extended Protection for Authentication (EPA), and deploy Windows Defender Credential Guard.
What is the difference between LDAP signing and LDAPS?
LDAP signing adds a cryptographic signature to LDAP protocol messages to detect tampering, but traffic is not necessarily encrypted. LDAPS (LDAP over SSL/TLS on port 636) encrypts the entire LDAP session. LDAPS provides both confidentiality (encryption) and integrity (tampering detection). LDAP signing on port 389 provides integrity only, without confidentiality. For maximum security, use LDAPS (port 636) plus LDAP signing. Channel binding adds the additional protection of tying the LDAP session to the specific TLS connection, preventing TLS stripping attacks.
Can I force LDAP signing without affecting Kerberos authentication?
Yes. LDAP signing and channel binding apply only to LDAP protocol traffic. Kerberos authentication (which is the default and preferred authentication protocol for domain-joined Windows clients) is not affected. Kerberos does not use LDAP port 389 or 636 for authentication -- it uses the Kerberos ports (88/UDP and 88/TCP). LDAP signing enforcement will not break Kerberos-authenticated resources.
How do I handle network printers that cannot use LDAPS?
Network printers that only support unsigned LDAP on port 389 cannot be made to work with LDAP signing enforcement. Options: (1) Migrate to cloud print solutions (Universal Print in Microsoft 365) that eliminate LDAP-based print authentication, (2) Use a dedicated read-only domain controller (RODC) or LDAP proxy (such as OpenLDAP with SASL signing) that sits between the printers and production DCs, (3) Accept the printers as a documented exception and network-isolate them so their unsigned LDAP traffic is limited to the print management VLAN only.
Does enabling LDAP channel binding break LDAPS connections?
No. LDAP channel binding applies to LDAP sessions that use SASL authentication (Negotiate/Kerberos/NTLM) on standard port 389. LDAPS (port 636) establishes a TLS tunnel first, and SASL authentication occurs inside the TLS session. Channel binding on LDAPS is different from the domain controller's CBT (Channel Binding Token) enforcement for port 389. Enabling LDAP channel binding on the domain controller does not affect LDAPS connections from clients that use LDAPS correctly. The concern with channel binding is applications that use port 389 SASL without CBT support, not applications using LDAPS.
How do I identify which applications in my environment do not support LDAP signing?
Enable LDAP diagnostic logging on domain controllers to capture unsigned and unencrypted LDAP binds. Set the registry value HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics\16 LDAP Interface Events to 2 (Basic). This causes Event ID 2886 (unsigned LDAP bind warning) and Event ID 2887 (unsigned LDAP connection statistics) to appear in the Directory Service event log. After 24 hours, review Event 2887 for the count of unsigned binds and the source IP addresses and application names performing them. Microsoft also provides a script (Get-LDAPClientSettings.ps1) that enumerates which machines are making unsigned LDAP connections. Address each application before setting the domain LDAP signing requirement to Required, as setting Required blocks unsigned clients immediately.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
