Bcrypt Cache Key Vulnerability in Okta’s AD/LDAP Authentication: Lessons Learned
Newly, I stumbled upon a security advisory from Okta that is of the utmost importance. On October 30th, they disclosed and addressed a vulnerability in their AD/LDAP delegated authentication system that had been present since July 23rd, 2024. What’s remarkable about this case is the vulnerability and the stark example of the potential pitfalls in cryptographic implementations, emphasizing the need for extreme caution and a stringent review cycle while implementing them.
The issue arose from how Okta generated cache keys for Active Directory (AD) and LDAP authentication. They were using Bcrypt, a widely accepted and reliable option for password hashing, to hash a combination of the user ID, username, and password. Although Bcrypt is generally a reliable option for password hashing, it has certain limitations that cause problems in this situation. The limits occur particularly when dealing with usernames longer than 52 characters.
Here’s a hypothetical example in Python of how this might work:
The Problem Pattern
Problem patterns often arise from edge cases. In this case, the issue was with the composite string that was hashed. Consider the following example:
- user_id: “12345”
- username: “very_long_username_that_exceeds_52_characters_and_gets_truncated_here”
- password: “secretpass”
The composite string might exceed Bcrypt’s 72-byte limit, causing the password portion to be effectively ignored in the hash calculation. This means two different passwords could potentially generate the same cache key under specific conditions.
Let’s break down why this matters. In normal operation, when AD/LDAP authentication is unavailable (think network issues or high traffic), Okta and other systems like them return to a cached authentication state. The vulnerability meant that someone could authenticate using a cached key from a previous successful login under specific conditions, such as when the system is under high load or when the network is experiencing issues.
The good news? The exploitation window was relatively narrow. You needed several conditions to align:
- AD/LDAP delegated authentication had to be in use
- No MFA protection (This would have completely halted the exploit.)
- The username had to be 52+ characters
- A previous successful authentication cache had to exist
- The system needed to hit the cache first
Okta’s fix was straightforward but telling. They switched from Bcrypt to PBKDF2 for the cache key generation. Cryptographic algorithms must be chosen not just for their security properties but also for how they handle edge cases in your specific use case.
Here is how a reliable implementation in Python could look like:
Lessons Learned
For organizations running similar systems, here are some key takeaways:
- Always implement MFA.
- Monitor logs.
- Consider implementing phishing-resistant authenticators (FIDO2)
What impresses me most is Okta’s rapid response. I am writing about the “same-day discovery” and their patching show solid security practices. However, the vulnerability’s existence for three months reminds us that even well-resourced security teams can miss edge cases during testing.
But make no mistake, any authentication system is a beast. Seemingly minor implementation details can have significant security implications. We need to understand more than strong cryptographic algorithms; we need to understand their limitations and how they interact with our specific use cases. And especially think of the edge cases.