SMS one-time codes are the most common way apps verify a user, and the weakest. A code texted to a phone number can be intercepted, phished in real time, or stolen outright when an attacker takes over the number through a SIM swap, and none of that requires breaking your app. SMS verification is still better than nothing, but if it is the only thing standing between an attacker and an account, that account is more exposed than it looks. Here is why SMS OTP is weak, how SIM swapping works, and how to use it more safely or move beyond it.
Short answer
SMS one-time passcodes (OTPs) are widely used but the weakest verification method, because the code travels over SMS, which can be intercepted, phished in real time, or stolen when an attacker takes over the victim's phone number through a SIM swap. Per OWASP, SMS is not a secure channel, so SMS OTP should not be your only protection for high-value accounts. Prefer stronger factors like authenticator apps or passkeys, and if you use SMS, rate-limit sending and verification, keep codes short-lived and single-use, bind the code to your app with the platform autofill mechanisms, and verify on your server. SMS OTP raises the bar over a password alone but does not resist a determined attacker.
What you should know
- SMS OTP is the weakest factor: the code travels over an insecure channel.
- SIM swap takes over the number: the attacker then receives the codes.
- Real-time phishing relays codes: an attacker proxies the OTP as the user enters it.
- Prefer stronger factors: authenticator apps or passkeys where possible.
- Harden it if you use it: rate limits, short expiry, single use, app binding.
Why is SMS OTP the weakest factor?
Because the code is delivered over a channel that can be intercepted or redirected, and the attacks do not touch your app. The table lists the main weaknesses.
| Weakness | How it is exploited |
|---|---|
| SIM swap | Attacker ports the victim's number and receives the codes |
| SMS interception | Network-level or malware interception of texts |
| Real-time phishing | A phishing page relays the OTP as the user types it |
| SMS not encrypted | Codes travel in plaintext over the carrier network |
| Toll fraud / SMS pumping | Attackers abuse your send endpoint to generate costs |
The common thread is that SMS was not designed as a secure authentication channel, so a code sent that way can be obtained without compromising your app or the user's device. Real-time phishing is especially relevant, since an attacker can stand up a fake login that relays whatever code the user enters, defeating the OTP even without intercepting the SMS. And the send endpoint itself can be abused to run up SMS costs.
What is a SIM swap?
It is an attacker taking control of the victim's phone number. In a SIM swap, the attacker convinces or tricks the mobile carrier into transferring the victim's number to a SIM the attacker controls, often using social engineering or stolen personal details, after which every SMS to that number, including your one-time codes, goes to the attacker. Because so many services use SMS for verification and account recovery, a successful SIM swap can cascade into taking over multiple accounts. The victim typically notices only when their own phone loses service. This is the attack that makes SMS OTP fundamentally fragile for high-value accounts: the second factor is tied to a phone number, and a phone number can be stolen through the carrier rather than through your security, which you cannot control.
How do you use SMS OTP more safely, or avoid it?
Prefer stronger factors, and harden SMS if you must use it. The best move is to offer an authenticator app or passkeys as the primary second factor and treat SMS as a fallback, since those resist SIM swap and interception. Where you do use SMS, harden it: rate-limit both sending and verification to stop brute-forcing and cost abuse, keep codes short-lived and single-use, and verify them on your server. Bind the code to your app using the platform mechanisms, the one-time-code autofill on iOS and the SMS Retriever or autofill on Android, and a domain-bound code format, so the code is associated with your app and harder to phish into a fake page. For high-value actions and account recovery especially, do not rely on SMS alone. The aim is to reduce SMS OTP's exposure where it is used and to not make it the sole gate on anything that matters.
What to watch out for
The first trap is using SMS OTP as the only protection for high-value accounts, when SIM swap and phishing can defeat it; offer a stronger factor. The second is leaving the OTP send and verify endpoints without rate limits, which enables brute-forcing codes and SMS-cost abuse. The third is a code that is long-lived or reusable, or not bound to your app, which makes phishing easier. SMS OTP is a backend and design matter, so a pre-submission scan such as PTKD.com (https://ptkd.com), which reads your app against OWASP MASVS, checks the surrounding credential and token handling rather than the SMS flow itself; the OTP logic and limits live on your server.
What to take away
- SMS one-time codes are the weakest verification method, because the code travels over an insecure channel and can be intercepted, phished, or stolen via SIM swap.
- A SIM swap lets an attacker take over the victim's phone number and receive the codes, which you cannot prevent through your app's security.
- Prefer authenticator apps or passkeys, treat SMS as a fallback, and do not use SMS alone for high-value accounts or recovery.
- If you use SMS, rate-limit sending and verification, keep codes short-lived and single-use, bind them to your app, and verify on your server.



