Login and registration return 500 when the User-Agent exceeds 255 characters
Checklist
- I could not find a solution in the existing issues or docs.
- I agree to follow this project's Code of Conduct.
Describe the bug
Login and registration return a 500 when the client sends a User-Agent longer than 255 characters, with session.acquire_user_agent on (the default). The password or passcode is verified first, so the visitor answers correctly and then gets "Something went wrong" with no session.
The session insert fails with:
the action failed to handle the request: failed to execute before state hook (state: success): failed to store session: failed to store session: named insert: ERROR: value too long for type character varying(255) (SQLSTATE 22001)I hit it in production from the Instagram in-app browser on Android, which sends 278 characters:
Mozilla/5.0 (Linux; Android 16; SM-S911B Build/BP4A.251205.006; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/152.0.7977.69 Mobile Safari/537.36 Instagram 445.0.0.45.83 Android (36/16; 480dpi; 1080x2340; samsung; SM-S911B; dm1q; qcom; nl_NL; 1055488490; IABMV/1)I have not debugged the backend, so the cause below is a guess from reading the source. sessions.user_agent is declared as an unsized fizz string in 20241002113000_create_sessions.up.fizz, which fizz maps to VARCHAR (255) on Postgres (translators/postgres.go), and the header is stored verbatim in hook_issue_session.go. Whether the fix is truncating before the insert, widening the column, or something else is your call.
Reproducing the bug
- Run the backend against Postgres with
session.acquire_user_agent: true. - Complete a login or a registration from a client sending a User-Agent over 255 characters against the flow API, or open the app in an Instagram or Facebook in-app browser.
- The
beforehook of thesuccessstate fails and the request returns 500technical_error. No session row is written and no token is issued.
I reproduced this locally with the 278-character string above on both password_login and registration. A 111-character User-Agent on the same build succeeds, and so does any login with acquire_user_agent: false.
Logs
POST /login?action=password_login@... status 500 error technical_error
the action failed to handle the request: failed to execute before state hook (state: success): failed to store session: failed to store session: named insert: ERROR: value too long for type character varying(255) (SQLSTATE 22001)Configuration
session:
acquire_user_agent: trueHanko Version
v2.7.0
OS Hanko Backend
Linux
OS Version Hanko Backend
Docker Compose, backend on Linux, Postgres. Client: Instagram in-app browser on Android 16.
OS
Other
OS Version
No response
Browser Version
No response
Environment
None
Additional Context
I work around it by trimming the User-Agent to 255 characters in the reverse proxy in front of Hanko. Setting session.acquire_user_agent: false also avoids it, at the cost of the user agent on the profile session list.
audit_logs.meta_user_agent is declared the same way in 20220818111000_create_audit_logs.up.fizz, so the same overflow looks reachable there.
Source: teamhanko/hanko