Forgejo Security Release 1.18.5-0

Today Forgejo v1.18.5-0 was released.

This release contains an important security fix for Forgejo to raise the protection against brute force attack on hashed passwords stored in the database to match industry standards, as described below.

This release also contains bug fixes, as detailed in the release notes.

We strongly recommend that all Forgejo installations are upgraded to the latest version as soon as possible.

If PASSWORD_HASH_ALGO is explicitly set in app.in, comment it out so that the stronger algorithm is used instead.

All password hashes stored with another algorithm will be updated to the new algorithm on the next usage of this password (e.g. a user provides the password to the Forgejo server when they login). It does not require manual intervention.

High CPU usage after the upgrade

The default password hashing in Forgejo now takes 32 times more CPU time. If the CPU usage is too high after the upgrade, the easiest workaround is to revert to the previous hash algorithm by adding the following in app.ini:

[security]
PASSWORD_HASH_ALGO = pbkdf2_v1

The real solution is to reduce the use of passwords in git commands or API calls and switch back to the default hash algorithm for better protection.

Reducing the performance impact

Codeberg hosts ~60,000 projects for ~50,000 users and provided real world data to evaluate the performance impact of using a hash algorithm that requires 32 times more CPU than before.

Password hashing happens when users login, sign up or reset their passwords. Even on a busy instance such as Codeberg it does not happen frequently enough to cause performance problems.

It is also possible that passwords are used in other contexts:

  • git commands, e.g. git clone https://user:password@forgejo.example.com/owner/repo/
  • API calls, e.g. curl https://user:password@forgejo.example.com/api/v1/version

They can be replaced by alternative authentication methods:

  • git commands can use SSH keys, e.g. git clone git@forgejo.example.com:owner/repo
  • API calls can use access tokens, e.g. curl -H 'Authorization: token xyz' https://forgejo.example.com/api/v1/version

It will be faster for the user because the hashing adds a delay. And it will significantly reduce the CPU usage on the Forgejo server.

Understanding password hashes

Brute force attacks

The user provided passwords are hashed before they are stored so they are not readable in case a copy of the database is leaked. The hash value stored in the database cannot be translated into the original password. But there exists large databases of common passwords and a program can patiently try to hash them one after the other, hoping to find a match. If the hash algorithm is fast, this brute force attack may succeed quickly. If the hash algorithm is expensive to run, it may take so long and use so much resources that it is not worth a try.

In other words, if a malicious person gets a copy of a Forgejo database, the complexity of the hash algorithm is the only thing preventing them from brute forcing it.

Industry standards

The industry adapt the recommendations for the hash algorithms as new hardware provide more processing power and make it easier to brute force. The default algorithm for Forgejo is PBKDF2-HMAC-SHA256 and the OWASP recommendations in December 2022 were:

use PBKDF2 with a work factor of 310,000 or more and set with an internal hash function of HMAC-SHA-256.

This security upgrade sets the iterations (work factor) to 320,000 and will be revised on a regular basis. Although the default for Forgejo is PBKDF2 and the upgrade consists of modifying its parameters, other algorithms such as argon2id may be preferred in the future.

Access tokens

In order for a brute force attack on a password hash to succeed, there must be a match in a database of common passwords. Since the access tokens are randomly generated by the Forgejo server, they are highly unlikely to be in such databases. That makes them, by nature, very resistant to brute force attacks.

Responsible disclosure to Gitea

On 8 February 2023 the Forgejo security team notified the Gitea security team that the default hash algorithm was significantly weaker than the industry standard, explained the associated risks and provided a patch to upgrade the hash algorithm to 320,000 iterations. An embargo was then negotiated until 16 February 2023, after which the v1.18 point release could be prepared.

Contribute to Forgejo

If you have any feedback or suggestions for Forgejo, we’d love to hear from you! Open an issue on our issue tracker for feature requests or bug reports. You can also find us on the Fediverse, or drop by our Matrix space (main chat room) to say hi!