During the first half of 2021 an external specialist conducted a security analysis of ZITADEL. We want to show you the results, what we already did and what we’re planning to do in the future.
The overall result was rated as good with only one high issue, which we already mitigated partially. Other issues were minor but nonetheless important for us and were fixed within a few days. Others still need more thinking from our side to find a solution that not only solves the immediate risk, but also gives the users a real benefit. Until then a lot of the findings can be mitigated from the users themself by using either Passwordless (WebAuthN) or at least by protecting their accounts with a second factor (2FA).
In the following section I will give you a short summary and comment on the highest ranked issues. The number indicates the external assessment according to the Common Vulnerability Scoring System (CVSS). You can find the full report here.
8.1 Data not Encrypted at Rest (CVSS 8.2 / High)
“The ZITADEL Console web application does not encrypt data at rest. An attacker with access to the database, can access the stored secret and personal identification information data.”
Although ZITADEL does not encrypt its database, the storage (hard disks) is encrypted. Furthermore, ZITADEL either hashes (bcrypt) or encrypts (AES) certain events for example passwords, OTP Secrets, private keys or temporary codes.
8.2 Failed Login Attempts Not Displayed (6.5 / Medium)
“The ZITADEL Console web application does not display failed login attempts after a successful authentication. An attacker may profit of this missing control, since a user will not know, that he was subject to an attack.”
We certainly lack a corresponding display and we’re planning to have such in the near future. For the moment a user is able to see these and all other events that have occurred on his user on the “Personal Information” page in the “Activity” section:
To mitigate the risk of an attacker attempting to log into your account, we highly recommend using Passwordless (WebAuthN) or at least protect your account with a second factor (2FA) for example Universal Second Factor (U2F) or One Time Password (OTP). ZITADEL allows managers to enforce the use of multi factor or passwordless authentication.
8.3, 8.4, 8.6 Missing Protections for Username / Password Authentication
I would like to take a look at the three points together, because the focus is on protecting authentication using usernames and passwords. To say it in advance, these can be mitigated considerably by using WebAuthN or at least a 2FA mechanism:
- 8.3 Missing Protection Against Online Guessing (6.5 / Medium):
“The ZITADEL Console web application does not protect user accounts with an application layer mitigation mechanism against automated brute-force attacks. An attacker with access to the login page can perform an online brute-force attack to guess a user’s password.”
- 8.4 Consider Restriction of Common or Compromised Passwords (6.5 / Medium):
“The ZITADEL Console web application does not offer the option for IAM Administrators to restrict the usage of common and compromised passwords. An attacker can be successful using a wordlist based brute force attack to takeover user accounts.”
- 8.6 Username Enumeration Possible (4.3 / Medium):
“The ZITADEL Console web application login allows enumeration of usernames, due to a warning that is showed after entering a non-existing username. An attacker with access to the login page can perform an online brute-force attack to enumerate existing usernames.”
To mitigate against brute-force attacks at least on a network layer, we use an IP-based rate limiting for our cloud service and dedicated instances. While we also provide a possibility to create a lockout policy, we do not recommend using it, as it also enables attackers to Denial-of-Service a user. Therefore a reasonable solution would be to use Captchas and prompt users to solve it when a user fails to enter a correct password multiple times.
When using a weak password an attacker's chance to take over an account is even higher. Giving organisation administrators the possibility to restrict certain passwords or make users aware that the password they use, might be weak or compromised will be an enhancement we plan to implement in the future.
We’ve discussed a lot whether we should show a warning that the entered username does exist or not. But the fact that a user can authenticate using external identity providers (e.g. Google) somewhat made it obsolete, because when the user enters their username, we might have to redirect them to their identity provider, which will disclose the fact that the user exists. Moreover, a malicious user who already has access to ZITADEL might gain access to this information anyway (e.g. through the client application).
8.5 IAM Policies Not Enforced (5.3 / Medium)
“The ZITADEL Console web application fails to disable user registration and password authentication on the server-side. An attacker who knows the technical details, on how to register a user, can register a user without access to any projects or organization information.“
A registration of a user, which would not have been allowed is certainly a problem and we fixed it. However, there are possible measures and facts that mitigate this issue. First of all a successful registration only allows a user to authenticate, which he might already be able to do so in another organisation, but no authorization to any project is granted by default. So if applications do their supposed authorization checks, they will not have a problem. As the user will not get any manager role within ZITADEL, he will as well not gain access to any information of other users of his organization.
8.7 Verbose Error Messages (4.3 / Medium)
“The ZITADEL Console web application shows verbose error messages in the HTTP Header Grpc-Message. This information can be helpful for an attacker to mount further attack steps.”
Due to the fact that ZITADEL is OpenSource, a lot of this information can be obtained anyway. But we definitely see room for improvement here, especially from a usability aspect and we will continuously improve this.
8.8 Consider Usage of Refresh Token (3.3 / Low)
During the security analysis, refresh tokens could not be tested because we were still implementing them. We released this feature the following week (see v1.8.0)
8.9 Logout Does Not Terminate Session (3.3 / Low)
Although this was only rated as low (3.3), we wanted to solve this issue quickly. We also found a bug where we would terminate the session and delete it from the database table. But when we did a query, we would make sure to apply newer events to the found session (using the event sequence of the found session). At first glance this totally makes sense, because the projection might be a little behind and a new session might not even be in the database, yet. The problem was that exactly this piece of code did not handle the logout event. This was an easy but important fix we provided a couple of days after the security test. It also demonstrated to us that we need more automated tests on the query side of our APIs.
What we are planning to do
We have a fast forward strategy and while we’re releasing a lot of new features frequently , we need to keep code and application security in mind. Therefore, we want to challenge our security from the outside more often and plan to do such security audits at least every six months. Moreover we have a basic responsible disclosure policy that we want to expand further over the near future, most likely coupled with an official bug bounty program.
Furthermore we will have to use the potential we gain through our CQRS / Eventsourcing architecture and generate use case based reports, e.g. present a user not only failed login attempts but also other relevant events that have taken place since the last successful login, such as gaining or losing access to a project and so on.
And last but not least, we are going to push passwordless authentication (WebAuthN) further as this solves a lot of problems regarding compromised or weak passwords.