Skip to content

Security: API token not rotated on password change #1076

@philayres

Description

@philayres

Summary

When a user changes their password, the authentication_token (API token used for simple_token_authentication) is not rotated. This means a stolen API token remains valid even after a user secures their account by changing their password.

Location

  • app/models/concerns/standard_authentication.rbhandle_password_change method (around line 455)
  • Currently clears locked_at, failed_attempts, unlock_token but does not rotate authentication_token

Additional Concern: Plaintext Token Storage

The authentication_token column in the users table is stored as a plain varchar string — not hashed. A database breach would directly expose all API tokens.

  • db/schema.rb line 1804: t.string "authentication_token", limit: 30

Impact

  • HIGH: If an API token is compromised (e.g., from logs, URL query params, or a database breach), the token remains valid indefinitely, even after the user changes their password.
  • API tokens are passed via URL query params (?user_token=xxx) which means they appear in web server logs, browser history, and proxy logs.

Recommended Fix

  1. Rotate authentication_token in handle_password_change when password_changed? is true
  2. Consider hashing the token (store a digest, compare on lookup) similar to how Devise stores password hashes
  3. Consider moving token transmission from URL query params to HTTP headers

Regression Specs

Security regression spec added at:

  • spec/controllers/security/api_token_rotation_on_password_change_spec.rb

This spec currently documents the insecure behavior (3 examples, 0 failures). Once the fix is applied, update the expectation in the 'does NOT rotate' test to verify the token IS rotated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    securitySecurity issue or CVE in dependency

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions