In this article
Explore the key concepts, practical considerations, and frequently asked questions related to otp sms security best practices: a complete guide for indian businesses (2026).
Key takeaways
- A 4-digit OTP has only 10,000 combinations and is trivially brute-forceable, so 6 digits with a lockout after 3 failed attempts is the RBI baseline.
- SIM swap fraud redirects a victim's OTPs to an attacker's new SIM, a risk app-based TOTP avoids since its secret never travels over the telecom network.
- Financial transaction OTPs should expire within 3-5 minutes and be invalidated immediately after first use, never left reusable for the full validity window.
SMS OTPs are the de facto standard for two-factor authentication in India- from banking and fintech to e-commerce and healthcare. But as adoption has grown, so have the attack surfaces. This guide covers every major OTP SMS security threat and the implementation patterns that mitigate them.
Why OTP SMS Security Matters in India
RBI mandates SMS-based two-factor authentication for most online financial transactions in India. NPCI's UPI, net banking, and card-not-present e-commerce transactions all rely on OTP verification. A compromised OTP flow doesn't just expose a single account- it can result in regulatory penalties, customer compensation liabilities, and permanent reputational damage.
Understanding and hardening every layer of your OTP implementation is not optional. It is a compliance and business continuity requirement.
Threat Model: What Can Go Wrong
Before implementing countermeasures, understand the attack surface:
| Threat | Attack Vector | Likelihood |
|---|---|---|
| OTP interception | SS7 protocol exploit | Low (targeted) |
| SIM swap fraud | Social engineering at telco | Medium |
| OTP bombing | Scripted request flooding to one victim | High |
| SMS pumping | Bots requesting OTPs to many numbers to inflate your SMS bill | Medium–High |
| Phishing | Fake login pages | High |
| Brute force | Guessing short OTPs | Medium |
| Client-side exposure | OTP logged or leaked in frontend | Medium |
| Template injection | Malicious input in OTP message | Low |
Best Practice 1- Generate Cryptographically Secure OTPs
Never use Math.random() or Date.now() to generate OTPs. These are not cryptographically secure and can be predicted or reverse-engineered.
Correct Approach (Node.js)
import { randomInt } from "crypto"; // Node.js built-in
function generateOtp(digits = 6): string {
const min = Math.pow(10, digits - 1);
const max = Math.pow(10, digits) - 1;
return randomInt(min, max + 1).toString();
}
Python
import secrets
def generate_otp(digits: int = 6) -> str:
lower = 10 ** (digits - 1)
upper = 10 ** digits
return str(secrets.randbelow(upper - lower) + lower)
Use 6 digits minimum. A 4-digit OTP has only 10,000 combinations- trivially brute-forceable. 6 digits with a lockout after 3 failed attempts is the RBI baseline.
Best Practice 2- Store OTP Hashes, Never Plaintext
Your database should never store the OTP in plaintext. Store a bcrypt or Argon2 hash alongside the expiry timestamp.
import bcrypt from "bcrypt";
async function storeOtp(mobile: string, otp: string) {
const hash = await bcrypt.hash(otp, 10);
const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes
await db.otps.upsert({
where: { mobile },
create: { mobile, hash, expiresAt, attempts: 0 },
update: { hash, expiresAt, attempts: 0 },
});
}
async function verifyOtp(mobile: string, input: string): Promise<boolean> {
const record = await db.otps.findUnique({ where: { mobile } });
if (!record || record.expiresAt < new Date()) return false;
if (record.attempts >= 3) throw new Error("OTP locked after 3 failed attempts");
const isValid = await bcrypt.compare(input, record.hash);
if (isValid) {
await db.otps.delete({ where: { mobile } }); // single use
} else {
await db.otps.update({ where: { mobile }, data: { attempts: { increment: 1 } } });
}
return isValid;
}
Best Practice 3- Enforce Short Expiry Windows
| Use Case | Recommended Expiry |
|---|---|
| Financial transaction OTP | 3–5 minutes |
| Login / account access | 5–10 minutes |
| Registration verification | 10–15 minutes |
| Password reset | 10 minutes |
Always invalidate the OTP on first use. An OTP that can be used multiple times within its validity window is a significant vulnerability- a stolen OTP remains exploitable for the full window.
Best Practice 4- Rate-Limit OTP Requests (OTP Bombing Prevention)
OTP bombing is one of the most common attacks against SMS-based auth in India. Implement multi-layer rate limiting:
Per-Number Limit
import { createClient } from "redis";
const redis = createClient();
async function checkOtpRateLimit(mobile: string) {
const key = `otp_req:${mobile}`;
const count = await redis.incr(key);
if (count === 1) await redis.expire(key, 3600); // 1-hour window
if (count > 5) {
throw new Error("Too many OTP requests. Try again in 1 hour.");
}
}
Per-IP Limit
Apply a secondary limit on the requesting IP address to prevent distributed attacks using multiple mobile numbers.
CAPTCHA on the Request Form
Add Google reCAPTCHA v3 or hCaptcha to your OTP request form. This blocks automated scripted submissions without adding friction for genuine users.
Stop SMS Pumping: Fake OTP Requests That Drain Your Budget
OTP bombing targets one victim's number. SMS pumping targets your budget: bots request OTPs to large numbers of different phone numbers, often in specific number ranges, so the attacker can profit from the SMS traffic or simply run up your costs. Per-number limits alone don't stop it, because every request goes to a different number.
Detection Signals
| Signal | What it looks like |
|---|---|
| Verification rate drops | Many OTPs sent, few entered. The share of OTPs verified falls well below your normal baseline |
| Sequential or clustered numbers | Requests to consecutive numbers, or many numbers sharing the same prefix |
| Unusual destinations | Sudden traffic to number ranges or countries you don't normally serve |
| Request bursts | Spikes at odd hours, or from a small set of IPs, devices, or user agents |
| No follow-up activity | Requests never followed by a code entry, login, or sign-up step |
Layered Rate Limits
Combine limits so an attacker can't get around one by rotating another:
- Per number: for example 5 per hour (see Best Practice 4)
- Per IP and per device fingerprint: stops one source from cycling through numbers
- Per number prefix: caps how many OTPs a single number range can receive in an hour
- Per destination country: if you only serve India, reject or challenge non-Indian numbers
Escalate the Challenge
Don't put every user through a hard CAPTCHA. Escalate only when signals look abnormal:
- Normal traffic: invisible bot check (for example reCAPTCHA v3 or Turnstile)
- Elevated risk score, or the source has hit a limit: visible challenge
- Clear abuse: block the source and require a different verification method
Spend Caps and Alerts
// Daily OTP budget guard- block sends above the cap and alert the team
async function checkOtpBudget() {
const key = `otp_sent:${new Date().toISOString().slice(0, 10)}`;
const sentToday = await redis.incr(key);
if (sentToday === 1) await redis.expire(key, 86400);
const DAILY_CAP = Number(process.env.OTP_DAILY_CAP); // e.g. 3x your normal daily volume
if (sentToday === Math.floor(DAILY_CAP * 0.8)) await alertTeam("OTP volume at 80% of daily cap");
if (sentToday > DAILY_CAP) throw new Error("OTP daily cap reached");
}
Set the cap from your own normal volume, and also alert when the verification rate (OTPs verified ÷ OTPs sent) drops below your baseline over the last hour. That is often the earliest sign of pumping.
Defensive Checklist
- Per-number, per-IP, per-device, and per-prefix limits in place
- Non-serviced countries and number ranges blocked or challenged
- Invisible bot check on the OTP request, escalating to a visible challenge
- Daily spend cap with alerts at 80% and 100%
- Hourly verification-rate alert compared to your baseline
- OTP request logs kept with IP, device, prefix, and outcome (see Best Practice 9)
- A fallback plan when the cap is hit, such as voice OTP or app-based TOTP for existing users
These controls reduce abuse; they don't eliminate it. Review your thresholds after any spike. If you'd like a second look at your OTP flow, request an authentication review or see our authentication and security solutions.
Best Practice 5- Prevent Brute Force with Attempt Locking
Allow a maximum of 3–5 incorrect OTP entries before locking the session. Implement exponential backoff for repeated lock events from the same number.
const MAX_ATTEMPTS = 3;
const LOCKOUT_SECONDS = 900; // 15 minutes
async function validateAttempts(mobile: string) {
const key = `otp_lock:${mobile}`;
const locked = await redis.get(key);
if (locked) throw new Error("Account temporarily locked. Try again later.");
}
async function recordFailedAttempt(mobile: string, currentAttempts: number) {
if (currentAttempts + 1 >= MAX_ATTEMPTS) {
await redis.set(`otp_lock:${mobile}`, "1", { EX: LOCKOUT_SECONDS });
}
}
Best Practice 6- Mitigate SIM Swap Fraud
SIM swap fraud- where an attacker convinces a telecom operator to reassign a victim's number to a new SIM- is a growing threat in India, particularly for banking and fintech applications.
Detection Strategies
- Monitor SIM change events via TRAI's MNRP APIs or your telecom partner's hooks. If a SIM was recently swapped (within 24–72 hours), enforce an additional verification step.
- Device binding- tie the OTP flow to a specific registered device. If the OTP is being requested from a new device, require additional identity verification before sending.
- Transaction cooling period- after a SIM swap event is detected on a customer's number, block high-value transactions for 24–48 hours.
Offer App-Based TOTP as an Alternative
For high-risk operations, offer users the option to authenticate via TOTP (Time-based One-Time Password) using an authenticator app (Google Authenticator, Authy). TOTP is immune to SIM swap attacks because the secret is stored on the device, not delivered over the telecom network.
Best Practice 7- Craft Phishing-Resistant SMS Templates
Your OTP SMS template itself is a security control. A well-written template makes it harder for phishing sites to impersonate you.
Good Template
747291 is your Get Click Media login OTP. Valid for 5 minutes.
NEVER share this OTP with anyone- we will never ask for it.- GCMDIA
Why It Works
- States the platform name clearly- harder to replicate convincingly
- Includes an explicit "never share" warning
- Short expiry communicated to the user
- Sender ID is consistent and registered on DLT
Bad Template (Avoid)
Your OTP is 747291.- GCMDIA
This provides no context, no expiry, and no anti-phishing cue. A fake SMS with the same format would be indistinguishable to the recipient.
Best Practice 8- Secure Your API Credentials
Your OTP SMS API key is as sensitive as a database password. Mishandling it can expose your entire user base to OTP spoofing.
- Store API keys in environment variables, never in source code
- Rotate API keys periodically (every 90 days minimum)
- Use separate API keys for development and production environments
- Restrict API key permissions to only the required operations (send-only, no admin access)
- Monitor your SMS provider dashboard for unexpected volume spikes- a sudden surge may indicate a compromised key
Best Practice 9- Log and Monitor OTP Events
Build an audit trail for every OTP event- generated, delivered, verified, failed, expired. This serves two purposes:
- Fraud investigation- you can reconstruct the exact OTP flow for any transaction under dispute
- Anomaly detection- spikes in failed verifications, unusual geographic patterns, or abnormal volume from a single number are early signals of an active attack
Minimum Log Fields
{
"event": "otp_generated",
"mobile": "+91XXXXXXXXXX",
"ip": "203.0.113.42",
"userAgent": "Mozilla/5.0...",
"timestamp": "2026-06-19T10:23:45Z",
"purpose": "login",
"expiresAt": "2026-06-19T10:33:45Z"
}
Never log the OTP value itself- only the event metadata.
Best Practice 10- Use the Transactional Route with a Reputable Provider
The telecom route your OTP travels through directly affects delivery reliability and security. A low-cost shared route may co-mingle your messages with promotional traffic, introducing latency and increasing the risk of delays that push users to request multiple OTPs.
Use a provider that offers:
- A dedicated transactional route (DND-exempt, priority queue)
- Guaranteed delivery receipts via webhooks
- DLT-registered sender IDs and templates
- Sub-3-second delivery SLA
Compliance Checklist
Before going live with OTP SMS in India:
- DLT entity registration complete and approved
- Transactional sender ID registered and approved
- OTP message template registered and approved- no unapproved variable patterns
- OTP generated using
crypto.randomIntorsecrets.randbelow - OTP stored as a hash (bcrypt/Argon2), not plaintext
- Maximum 3–5 attempt lockout implemented
- Rate limiting active- max 5 OTP requests per number per hour
- OTP expires in 10 minutes or less; invalidated after single use
- SIM swap monitoring or device binding in place for high-risk flows
- API credentials stored in environment variables, not in code
- OTP events logged (without logging OTP values)
- Webhook delivery monitoring configured
Summary
OTP SMS security is a layered problem- no single control is sufficient. Cryptographic generation, hash storage, short expiry, strict rate limiting, attempt locking, phishing-resistant templates, and SIM swap awareness must all be implemented together to build a resilient OTP system for Indian users.
Get Click Media delivers OTPs via a TRAI DLT-compliant transactional route with sub-3-second delivery, webhook receipts, and full DLT registration support- giving you a secure foundation to build on.
Article topics
Frequently Asked Questions
Is SMS OTP secure for banking transactions in India?
SMS OTP is accepted by RBI as a valid second factor for banking transactions in India, but it is not immune to threats like SIM swap fraud and SS7 attacks. For high-value transactions, banks should combine SMS OTP with device binding, behavioural analytics, or app-based TOTP as an additional layer.
What is OTP bombing and how can businesses prevent it?
OTP bombing is an attack where a bad actor triggers hundreds of OTP requests to a victim's number, either as harassment or as a smokescreen to cover a fraudulent transaction. Prevent it by implementing strict rate limiting (e.g., max 5 OTP requests per number per hour), CAPTCHA on the request form, and alerting on abnormal OTP generation spikes.
How do I stop fake OTP requests draining my SMS budget?
Fake OTP requests that drain your budget are usually SMS pumping: bots request OTPs to many different numbers, often in number ranges where the attacker earns a share of the SMS revenue. Stop it with layered limits (per number, per IP, per device, and per number prefix), a bot challenge that escalates when traffic looks abnormal, a daily spend cap, and an alert when the share of OTPs that are actually verified drops. No single control stops all abuse, so monitor and adjust.
What is SIM swap fraud and how does it affect OTP SMS?
In a SIM swap attack, a fraudster convinces a telecom operator to transfer the victim's number to a new SIM card. All incoming SMS- including OTPs- then go to the attacker's device. Mitigate this by monitoring for recent SIM changes via telecom APIs, enforcing cooling periods after SIM swap events, and offering app-based OTP (TOTP) as an alternative.
How long should an OTP SMS be valid in India?
Industry best practice and RBI guidelines recommend OTP validity windows of 10 minutes or less for financial transactions. Shorter windows (3–5 minutes) reduce the risk of interception. Always invalidate the OTP immediately after a single successful use- never allow reuse.
About the author
Get Click Media creates practical resources for businesses using messaging, automation, analytics, and digital communication to improve customer engagement. This article was published on and was last reviewed on .

