CVE-2026-21622 Overview
CVE-2026-21622 is an Insufficient Session Expiration vulnerability discovered in the hexpm package manager (hexpm/hexpm) within the Elixir.Hexpm.Accounts.PasswordReset module. This critical flaw allows attackers to perform account takeover attacks by exploiting password reset tokens that never expire.
The vulnerability exists because password reset tokens generated via the "Reset your password" flow do not have any time-based expiration enforced. When a user requests a password reset, Hex sends an email containing a reset link with a token that remains valid indefinitely until used. This design flaw creates a significant attack surface where historical email data breaches can be weaponized to compromise accounts long after the initial password reset request.
Critical Impact
Attackers with access to leaked mailbox archives can use any unused password reset tokens to take over victim accounts without requiring current access to the victim's email account.
Affected Products
- hexpm/hexpm (commits from 617e44c71f1dd9043870205f371d375c5c4d886d before bb0e42091995945deef10556f58d046a52eb7884)
- lib/hexpm/accounts/password_reset.ex module
- Elixir.Hexpm.Accounts.PasswordReset:can_reset?/3 routine
Discovery Timeline
- 2026-03-05 - CVE CVE-2026-21622 published to NVD
- 2026-03-05 - Last updated in NVD database
Technical Details for CVE-2026-21622
Vulnerability Analysis
This vulnerability stems from a fundamental flaw in the password reset token lifecycle management within the hexpm application. The can_reset?/3 function in the password_reset.ex file only validated that the reset key matched and that the email was correct, without implementing any temporal validation. This allowed password reset tokens to remain valid indefinitely, violating secure session management principles outlined in CWE-613 (Insufficient Session Expiration).
The attack scenario is particularly dangerous because it does not require real-time access to a victim's email. If an attacker obtains access to historical email data through a data breach, leaked mailbox archive, or compromised backup, any unused password reset emails can be exploited months or even years after they were originally sent.
Root Cause
The root cause lies in the can_reset?/3 function within lib/hexpm/accounts/password_reset.ex. The original implementation only performed two validation checks:
- Whether the reset key matched the stored key
- Whether the primary email matched
The function completely lacked any time-based expiration check, allowing tokens to persist indefinitely. Additionally, the original key comparison used direct equality checking rather than a secure comparison function, potentially exposing the application to timing attacks.
Attack Vector
This vulnerability is exploitable over the network without requiring authentication or user interaction. An attacker can leverage this vulnerability through the following attack flow:
- Obtain access to a victim's historical email data (via data breach, leaked backup, or compromised archive)
- Locate any unused password reset emails from hexpm
- Extract the password reset token from the email link
- Submit the token to the password reset endpoint
- Set a new password and gain complete control of the victim's account
The attack can be executed remotely with no complexity barriers, making it particularly dangerous for high-value accounts or package maintainers on the Hex package registry.
# Vulnerable Code (before patch) - Source: https://github.com/hexpm/hexpm/commit/bb0e42091995945deef10556f58d046a52eb7884
}
end
- def can_reset?(%__MODULE__{} = reset, primary_email, key) do
- reset.key == key && reset.primary_email == primary_email
+ def can_reset?(reset, primary_email, key) do
+ valid_email? = primary_email == reset.primary_email
+ valid_key? = !!(reset.key && Hexpm.Utils.secure_check(reset.key, key))
+ within_time? = Hexpm.Utils.within_last_day?(reset.inserted_at)
+
+ valid_email? and valid_key? and within_time?
end
end
Source: GitHub Commit bb0e42091995945deef10556f58d046a52eb7884
Detection Methods for CVE-2026-21622
Indicators of Compromise
- Password reset tokens being used days, weeks, or months after their creation timestamp
- Successful password resets originating from IP addresses inconsistent with the account's historical access patterns
- Multiple accounts being reset from the same IP address or subnet in a short timeframe
- Password reset completions without corresponding recent password reset requests in application logs
Detection Strategies
- Implement logging and alerting for password reset token usage that correlates request time with completion time
- Monitor for anomalous patterns in password reset completion rates, particularly from geographic regions inconsistent with user profiles
- Audit historical password reset records in the database for tokens that remain unused but were created long ago
- Cross-reference password reset events with known data breach timelines to identify potentially compromised accounts
Monitoring Recommendations
- Enable comprehensive audit logging for all password reset request and completion events
- Configure alerts for password reset tokens older than 24 hours being successfully used
- Implement geographic and behavioral analysis for password reset completion events
- Regularly audit the password_reset database table for stale, unused tokens and consider purging them proactively
How to Mitigate CVE-2026-21622
Immediate Actions Required
- Update hexpm to the patched version containing commit bb0e42091995945deef10556f58d046a52eb7884
- Invalidate all existing password reset tokens in the database immediately
- Notify users about the security update and recommend password changes for accounts that may have had historical reset emails
- Review application logs for any suspicious password reset activity
Patch Information
The vulnerability has been addressed in commit bb0e42091995945deef10556f58d046a52eb7884. The fix implements three critical security improvements:
- Time-based expiration: Added within_time? check using Hexpm.Utils.within_last_day?(reset.inserted_at) to ensure tokens expire within 24 hours
- Secure key comparison: Replaced direct equality check with Hexpm.Utils.secure_check(reset.key, key) to prevent timing attacks
- Null safety: Added proper nil handling for the reset key
For additional details, see the GitHub Security Advisory GHSA-6r94-pvwf-mxqm.
Workarounds
- If immediate patching is not possible, implement a scheduled job to automatically expire password reset tokens older than 24 hours
- Add database-level constraints or triggers to invalidate old tokens
- Consider temporarily disabling the password reset functionality until the patch can be applied
- Implement additional authentication factors (2FA) to reduce the impact of password-only account compromise
# Example: Database cleanup for stale password reset tokens
# Run this query to invalidate all password reset tokens older than 24 hours
DELETE FROM password_resets
WHERE inserted_at < NOW() - INTERVAL '24 hours';
# Alternative: Mark tokens as expired rather than deleting
UPDATE password_resets
SET expired = true
WHERE inserted_at < NOW() - INTERVAL '24 hours'
AND expired = false;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


