Bug 2537840

Summary: CVE-2026-90462 sssd: SSSD: Fail-open in LDAP ppolicy access check allows continued authorization [fedora-all]
Product: [Fedora] Fedora Reporter: Marco Benatto <mbenatto>
Component: sssdAssignee: Alexey Tikhonov <atikhono>
Status: ASSIGNED --- QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: medium    
Version: rawhideCC: abokovoy, atikhono, lslebodn, pbrezina, sbose, ssorce, sssd-maintainers
Target Milestone: ---Keywords: Security, SecurityTracking
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard: {"flaws": ["9adc4d0c-226b-470a-a3b8-69a7111c3102"]}
Fixed In Version: Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2479483    

Description Marco Benatto 2026-09-22 13:49:21 UTC
Disclaimer: Community trackers are created by Red Hat Product Security team on a best effort basis. Package maintainers are required to ascertain if the flaw indeed affects their package, before starting the update process.

AI_ONLY_REPORT
package: sssd-2.12.0-1.el10
------
Summary: Fail-open in LDAP ppolicy access check when user lookup returns  
zero results: missing-user LDAP ppolicy lookups can incorrectly return  
success and cache an allow decision, permitting continued authorization for  
a deleted or deprovisioned user in affected configurations.
Requirements to exploit: SSSD must use `access_provider = ldap` with  
`ldap_access_order` including `ppolicy` or `lockout`, the target user must  
still have locally retained SSSD user state, the ppolicy LDAP lookup for  
that user must return zero entries, and a new access check must reach the  
online LDAP access path.
Component affected: `sssd-2.12.0-1.el10`,  
`src/providers/ldap/sdap_access.c`, `sdap_access_ppolicy_step_done()`
Version affected: `sssd-2.12.0-1.el10` when SSSD is configured with the  
LDAP access provider and `ldap_access_order` includes `ppolicy` or `lockout`
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: Not notified.
CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N - 5.3 (MEDIUM)
AV:N - The vulnerable authorization path can be reached through normal  
remote login or access flows that rely on SSSD.
AC:L - Once the affected configuration exists, the triggering condition  
is a zero-result LDAP lookup for the user.
PR:L - Exploitation requires prior valid account context; this is not  
anonymous access.
UI:N - No separate user interaction is required.
S:U - The flaw affects the same authorization boundary enforced by SSSD.
C:L - Successful exploitation can preserve access to information that  
should no longer be available to the deleted account.
I:L - The same stale authorization can permit limited modification of  
resources available to that account.
A:N - The available evidence does not show a direct availability impact.
Impact: Moderate. The flaw can preserve access for a deleted or  
deprovisioned account, which is a real confidentiality and integrity  
concern, but exploitation depends on a specific non-default LDAP  
access-control configuration and pre-existing account state. This is a  
meaningful security issue, but not an easily exploited default-path  
compromise.
Embargo: no
Reason: The issue is configuration-dependent, requires prior account  
context, and has straightforward operational mitigations pending a fix.
Acknowledgement: Aisle Research
Vulnerability Details: In `sdap_access_ppolicy_step_done()`, `locked` is  
initialized to `false`. When the base-scoped LDAP search returns zero  
results, the function logs that access is being denied but does not set a  
deny result. Execution then reaches the common tail, where `locked ==  
false` causes `ret = EOK`, and the code writes an allow-state cache entry  
for future checks.
```c
bool locked = false;
...
if (num_results < 1) {
DEBUG(SSSDBG_CONF_SETTINGS,
"User [%s] was not found with the specified filter. "
"Denying access.\n", state->username);
}
...
if (locked) {
DEBUG(SSSDBG_TRACE_FUNC,
"Access denied by online lookup - account is locked.\n");
ret = ERR_ACCESS_DENIED;
} else {
DEBUG(SSSDBG_TRACE_FUNC,
"Access granted by online lookup - account is not locked.\n");
ret = EOK;
}
...
tret = sdap_save_user_cache_bool(state->domain, state->username,
SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
!locked);
```
The analogous filter path treats `num_results < 1` as a deny condition and  
returns `ERR_ACCESS_DENIED`, so the ppolicy handling is a fail-open  
inconsistency. Based on the available evidence, the security consequence is  
an authorization bypass for previously known users after deletion or  
deprovisioning, not a broader unauthenticated compromise.
Steps to reproduce:
1. Configure SSSD with `access_provider = ldap` and `ldap_access_order =  
ppolicy` or `ldap_access_order = lockout`.
2. Ensure a test user exists, authenticates once, and remains present in  
SSSD state so local user lookup still succeeds.
3. Delete or move the user entry in LDAP so the base-scope lookup used by  
the ppolicy step returns zero results.
4. Perform a new login or access check for that username while the backend  
is online.
5. Observe a log sequence equivalent to `User [...] was not found with the  
specified filter. Denying access.` followed by `Access granted by online  
lookup - account is not locked.`
6. Observe that the final decision is success (`EOK`) and that the cached  
lockout allow flag is written as `true` (`!locked`).
Mitigation: Until a fix is available, avoid using `ppolicy` or `lockout` as  
the sole LDAP access decision where rapid deprovisioning enforcement is  
required. Clearing stale SSSD cache entries when users are removed from  
LDAP also reduces the exposure window because the reproduced condition  
depends on locally retained user state.
Proposed Fix: Explicitly deny access when the ppolicy lookup returns zero  
results so the function cannot fall through to the success path or cache an  
allow decision.
```diff
diff --git a/src/providers/ldap/sdap_access.c  
b/src/providers/ldap/sdap_access.c
index 0000000..0000000 100644
— a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -1953,6 +1953,8 @@ static void sdap_access_ppolicy_step_done(struct  
tevent_req *subreq)
if (num_results < 1) {
DEBUG(SSSDBG_CONF_SETTINGS,
"User [%s] was not found with the specified filter. "
"Denying access.\n", state->username);
+        locked = true;
+        ret = ERR_ACCESS_DENIED;
} else if (results == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is  
NULL\n");
ret = ERR_INTERNAL;
```
Setting either `locked = true` or `ret = ERR_ACCESS_DENIED` is sufficient;  
setting both makes the intended deny behavior explicit and prevents an  
allow-cache write.
------
This report was generated using AI technology. Always review AI-generated  
content prior to use