Ech0 'Never Expire' Access Tokens Cannot Be Revoked
Ech0's access tokens with the 'never expire' option cannot be revoked through logout or deletion, leading to persistent access until the JWT secret is rotated instance-wide.
Ech0, a self-hosted platform, has a vulnerability concerning the revocation of access tokens created with the “never expire” option. These tokens, lacking an exp (expiration) claim, bypass three revocation mechanisms. Specifically, the logout function panics when attempting to process these tokens due to a nil pointer dereference, while the admin’s “Delete token” function removes the database record without blacklisting the JTI (JWT ID). This means that if a “never expire” token is compromised, it remains valid until the JWT_SECRET is rotated, an action that affects all users on the platform. This issue was found by aisage.io. Version 4.5.6 is affected.
Attack Chain
- An administrator creates an access token with the “never expire” option. This token lacks the
expclaim in its JWT. - The attacker obtains a “never expire” token through theft or compromise (e.g., stolen laptop, exposed configuration file).
- The attacker uses the stolen token in an HTTP Authorization header to access protected resources. The middleware accepts the token since it has a valid signature.
- The legitimate owner attempts to revoke the token via logout. The logout handler attempts to parse the token and extract the expiration time.
- Parsing of the token in the logout handler leads to a panic because it attempts to access
.Timefield of a nilExpiresAtclaim (present only on tokens with expiry). The token revocation is skipped. - The administrator attempts to delete the access token via the admin panel. This action removes the metadata for the token from the database, but does not blacklist the JTI.
- The attacker continues to use the token for authorized requests, bypassing revocation attempts.
- The attacker maintains perpetual access to the system, leveraging the scopes associated with the stolen token.
Impact
Compromised “never expire” tokens grant attackers persistent authenticated access to Ech0 instances. This access remains valid until the JWT_SECRET is rotated, forcing a platform-wide reset. Administrators are misled by the “Delete token” function, which appears to revoke access but does not. The need to rotate the JWT_SECRET for proper revocation introduces a blast radius, requiring every user to log in again.
Recommendation
- Replace “never expire” tokens with very long-lived tokens, ensuring an
expclaim exists. See code example in the overview section. - Modify the logout handler to gracefully handle tokens with a nil
ExpiresAtfield. See code example in the overview section. - When deleting an access token through the admin panel, blacklist the corresponding JTI. See code example in the overview section.
- Rotate the JWT secret immediately if a “never expire” token is suspected of being compromised. This invalidates all active tokens and prevents further unauthorized access.
Detection coverage 2
Detect Ech0 API Logout Panic Due to Missing Expiration
mediumDetects HTTP 500 errors on the /api/auth/logout endpoint, indicating a potential panic due to a missing expiration claim in a 'never expire' token.
Detect Ech0 API Access Token Deletion Without JTI Blacklisting
lowDetects attempts to delete access tokens via the API endpoint without subsequent revocation, potentially indicating a failure in JTI blacklisting.
Detection queries are available on the platform. Get full rules →