Skip to content

bug: Phone number sanitisation #7371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mrfrase3 opened this issue May 9, 2025 · 3 comments
Open

bug: Phone number sanitisation #7371

mrfrase3 opened this issue May 9, 2025 · 3 comments
Assignees
Labels
bug Something isn't working status/wip We are working on it

Comments

@mrfrase3
Copy link

mrfrase3 commented May 9, 2025

Describe the bug

It's common to represent a mobile number in two ways:

  • With region code: 61 412 345 678
  • With local code: 0412 345 678 (will work between devices in the same region)

A non-discerning user (95% of users) is likely to input both, i.e. 61 0412 345 678, whilst technically incorrect, most phone validation libraries will chop off the 0 when parsing.

If you save the incorrect format via the admin console, the form does pass the value through the parsePhoneNumber util which strips the 0 and other formatting:
https://github.com/logto-io/logto/blob/master/packages/console/src/pages/Users/components/CreateForm/index.tsx#L87C56-L87C72
https://github.com/logto-io/logto/blob/master/packages/console/src/pages/UserDetails/UserSettings/index.tsx#L90

However, both the sign in and sign up experience flows do not, in fact they save/match purely on what the user types in.

So if there is a user with primaryPhone set to 61412345678 (from the console or signup) and they then enter 61 0412345678 during sign in, or vise versa, it will reject the users login attempt saying their account doesn't exist

The main culprit is here in the SmartInput component:

  useEffect(() => {
    onChange?.({
      type: identifierType,
      value: isPrefixVisible && inputValue ? `${countryCode}${inputValue}` : inputValue,
    });
  }, [countryCode, identifierType, inputValue, isPrefixVisible, onChange]);

It should be doing something like:

value: isPrefixVisible && inputValue
  ? parsePhoneNumber(`${countryCode}${inputValue}`)
  : inputValue,

But also this is a deeper issue, where this sanitisation is currently only occurring on the frontend. It should also be occurring in:
findUserByPhone
hasUserWithPhone
insetUser

This has likely caused a larger issue as this has been in production for a long time, so there are now unsanitised phone numbers in all tennant databases that had the feature enabled. :S

Expected behavior

When signing in, either format, invalid or not, should work and sign me in:

  • 61 412345678
  • 61 0412345678

What's saved in the database should be sanitised with parsePhoneNumber. i.e 61412345678

How to reproduce?

  1. Create a user with a number via the admin console
  2. try to sign in with the 0 variant and be rejected as the account doesn't exist (even though it does and an sms gets sent)

or

  1. register with the 0 variant, (610412345678) the user account will have the 0 variant saved in the database
  2. both the experience and console will render this phone number in the correct format (+61 412 345 678)
  3. sign in without the 0, it'll reject saying the user doesn't exist.

Environment

Logto Cloud

Screenshots

No response

@mrfrase3 mrfrase3 added the bug Something isn't working label May 9, 2025
@simeng-li simeng-li self-assigned this May 12, 2025
@simeng-li simeng-li added the status/wip We are working on it label May 12, 2025
@simeng-li
Copy link
Contributor

Hi @mrfrase3, thanks for your report. Working on the fix .

@simeng-li
Copy link
Contributor

simeng-li commented May 15, 2025

For existing users:

#7382
Enhanced the findUserByNormalizedPhone query method to allow users to sign in to their existing accounts using either phone number format — with or without the leading '0'.
The method cross-checks the input phone number against database records in both formats to ensure that legacy users who registered with a leading '0' can still access their accounts.

#7385
Enhanced the hasUserWithNormalizedPhone query method to validate phone number uniqueness in the database.
The method checks for existing users by matching the phone number in both formats — with and without the leading '0' — to ensure they are treated as the same number.
If a user exists with either format, the method will return a "phone number exists" result. This helps prevent new accounts from being registered using a different format of an already existing phone number.

For future registered phone number:
#5882
Normalize the phone number to a standard international format before inserting it into the database. This process strips any leading '0' from the input.
Additionally, the update includes validation of the phone number format before saving it to the database.

@mrfrase3 Thanks again for bringing this up. Please take a look at the fixes above — we’ll include them in the next release.

@mrfrase3
Copy link
Author

mrfrase3 commented May 15, 2025

Thanks @simeng-li and the rest of the team getting on this, hopefully I haven't ruined the sprint velocity for you guys 😅

I've taken a look and it all looks good.

Also worth noting that libphonenumber-js needs to be kept up-to-date somewhat frequently, as new number ranges are brought online all the time around the world, and if the lib isn't updated, you can start to get peoples new numbers rejecting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working status/wip We are working on it
Development

No branches or pull requests

2 participants