{"record":{"id":"d757cfb4eda3e6c1","repo":"instructure/canvas-lms","slug":"pseudonym-cannot-have-a-unique-id-of-length-credentials","errorCode":null,"errorMessage":"pseudonym cannot have a unique_id of length #{credentials[:unique_id].length}","messagePattern":"pseudonym cannot have a unique_id of length #(.+?)","errorType":"validation","errorClass":"ImpossibleCredentialsError","httpStatus":null,"severity":"warning","filePath":"app/models/pseudonym.rb","lineNumber":771,"sourceCode":"  scope :active_only, -> { where(workflow_state: \"active\") }\n  scope :deleted, -> { where(workflow_state: \"deleted\") }\n\n  def self.serialization_excludes\n    %i[crypted_password password_salt reset_password_token persistence_token single_access_token perishable_token sis_ssha]\n  end\n\n  def self.associated_shards(_unique_id_or_sis_user_id)\n    [Shard.default]\n  end\n\n  def self.find_all_by_arbitrary_credentials(credentials, account_ids)\n    return [] if credentials[:unique_id].blank? ||\n                 credentials[:password].blank?\n    if credentials[:unique_id].length > 255\n      # this sometimes happens by mistake, and produces noisy errors.\n      # we can handle this error explicitly when it arrives and just return\n      # a failed login instead of an error.\n      raise ImpossibleCredentialsError, \"pseudonym cannot have a unique_id of length #{credentials[:unique_id].length}\"\n    end\n\n    error = nil\n    begin\n      associated_shards = associated_shards(credentials[:unique_id])\n    rescue => e\n      # global lookups is just an optimization anyway; log an error, but continue\n      # by searching all accounts the slow way\n      Canvas::Errors.capture(e)\n    end\n    pseudonyms = Shard.partition_by_shard(account_ids) do |shard_account_ids|\n      next if GlobalLookups.enabled? && associated_shards && !associated_shards.include?(Shard.current)\n\n      active_only\n        .by_unique_id(credentials[:unique_id])\n        .where(account_id: shard_account_ids)\n        .preload(:user)\n        .select do |p|","sourceCodeStart":753,"sourceCodeEnd":789,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/pseudonym.rb#L753-L789","documentation":"Pseudonym raises ImpossibleCredentialsError during login credential processing when the supplied unique_id (login/email) exceeds 255 characters. Such credentials can never succeed because the column limit makes them impossible to match, and past behavior produced noisy errors instead of a clean failed login.","triggerScenarios":"A login attempt where credentials[:unique_id].length > 255 — e.g. a malicious or malformed POST to the login endpoint, a client bug concatenating values into the login field, or pasted oversized data into the login form.","commonSituations":"Bots or scanners submitting garbage to /login; SSO/LDAP misconfiguration sending oversized identifiers; user pasting a long string (e.g. a JWT or URL) into the email field; automated tests with invalid fixtures.","solutions":["Return a normal failed-login response instead of a 500 — the raise exists so callers rescue ImpossibleCredentialsError and treat it as bad credentials","Add client-side/server-side length validation (<= 255) on the login field before authentication","Investigate the client or integration producing >255-char unique_ids","Sanitize/trim login input at the edge (proxy, SSO adapter) before it reaches Pseudonym"],"exampleFix":"// before\nlogin(params[:pseudonym_session][:unique_id])\n// after\nuid = params[:pseudonym_session][:unique_id]\nif uid && uid.length > 255\n  return failed_login\nend\nlogin(uid)","handlingStrategy":"validation","validationCode":"uid = params.dig(:pseudonym_session, :unique_id)\nreturn failed_login if uid.blank? || uid.length > 255","typeGuard":"def valid_unique_id?(uid)\n  uid.is_a?(String) && uid.length.between?(1, 255)\nend","tryCatchPattern":"begin\n  authenticate(pseudonym_session)\nrescue ImpossibleCredentialsError\n  failed_login\nend","preventionTips":["Enforce a 255-char max on login/email inputs client- and server-side","Scrub login forms against pasted blobs (JWTs, URLs)","Check SSO/LDAP adapters for identifier truncation rules","Monitor for oversized unique_id attempts as bot traffic"],"tags":["authentication","validation","login","input-validation"],"backgroundTag":"value-out-of-range","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}