Privacy Tools Guide

Phone number spoofing occurs when a caller deliberately falsifies the caller ID information transmitted to disguise their identity. For developers and power users, understanding how to detect spoofing is essential for building secure communication systems and protecting personal privacy. This guide covers practical methods to check if your number is being used without authorization.

Understanding Phone Number Spoofing

Spoofing works because the traditional telephone network was built on trust. The Caller ID system (CNAM) relies on the calling party to provide accurate information, and there’s no built-in verification in legacy SS7 protocols. Modern VoIP systems make it trivial to forge the originating number.

The consequences of having your number spoofed include unwanted calls appearing to come from your number, potential reputation damage with carriers, and in severe cases, your number being blocked by spam filters or call protection services.

Method 1: Monitor Incoming Call Patterns

The first indicator of spoofing is unusual activity on your number. If you receive calls or text messages asking “Why did you call me?” when you didn’t, your number may have been cloned.

Create a simple logging script to track incoming calls:

#!/usr/bin/env python3
# spoofing_monitor.py
import os
from datetime import datetime

LOG_FILE = "call_log.txt"

def log_call(phone_number, call_type="unknown"):
    timestamp = datetime.now().isoformat()
    with open(LOG_FILE, "a") as f:
        f.write(f"{timestamp} | {call_type} | {phone_number}\n")

if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        log_call(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else "incoming")

While this won’t prevent spoofing, it helps establish a baseline. If you suddenly receive大量 callbacks or SMS replies to calls you never made, that’s a red flag.

Method 2: Use Carrier Lookup APIs

Several services provide phone number validation and reputation data. These APIs can help detect if your number has been flagged as a source of spam or spoofed calls.

Twilio Lookup API

curl -X GET "https://lookups.twilio.com/v2/PhoneNumbers/+15551234567" \
  -u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN

The response includes carrier information, caller ID name, and spam scores. Check if your number appears with unusual spam flags.

NumVerify API

curl -s "http://apilayer.net/api/validate?access_key=YOUR_KEY&number=15551234567"

This returns validity status, line type (landline, mobile, VoIP), and carrier details.

Google libphonenumber (Python)

from phonenumbers import carrier, geocoder, number_type

phone_number = "+15551234567"

# Get carrier information
carrier_name = carrier.name_for_number(phone_number, "en")
print(f"Carrier: {carrier_name}")

# Get number type
num_type = number_type(phone_number)
print(f"Type: {num_type}")  # 0=fixed, 1=mobile, 2=FIXED_LINE_OR_MOBILE, etc.

# Get geographic location
location = geocoder.description_for_number(phone_number, "en")
print(f"Location: {location}")

Method 3: Check STIR/SHAKEN Authentication

STIR (Secure Telephony Identity Revisited) and SHAKEN (Signature-based Handling of Asserted information using toKENs) are protocols designed to combat spoofing by verifying caller identity. While not yet universal, major carriers have implemented these standards.

Contact your carrier to ask:

Method 4: Monitor Call Detail Records

Request your call detail records (CDR) from your carrier. Look for:

# Simple CDR analyzer to flag suspicious patterns
def analyze_cdr(cdr_data):
    suspicious = []
    for call in cdr_data:
        # Flag calls to premium rate numbers
        if call.get("destination", "").startswith("1-900"):
            suspicious.append(f"Premium rate call: {call}")

        # Flag very short calls (potential toll fraud)
        if call.get("duration", 999) < 2 and call.get("direction") == "outbound":
            suspicious.append(f"Short duration call: {call}")

    return suspicious

Method 5: Set Up Number Monitoring Services

Several services can alert you when your number appears in suspicious contexts:

Have I Been Pwned (Phone Monitoring)

While primarily for email breaches, some services aggregate phone number exposures.

Call Defender Apps

Apps like Truecaller, Hiya, and Nomorobo maintain databases of reported spoofed numbers. Search your number in these databases to see if it’s been flagged.

CNAM Lookup

The Caller ID Name database can show what name displays when your number is called. Inconsistent CNAM information may indicate spoofing issues.

Prevention and Mitigation

Once you’ve confirmed spoofing, take these steps:

  1. Contact your carrier immediately - Report the spoofing and ask about call filtering options
  2. Enable caller verification - Services like STIR/SHAKEN provide authentication levels (full, partial, gateway)
  3. Consider a new number - If spoofing persists, changing your number may be the only solution
  4. Document everything - Keep logs of suspicious calls for potential law enforcement reports
  5. Register on Do Not Call list - The National Do Not Call Registry won’t stop spoofers but may reduce legitimate telemarketing

For Developers: Building Spoof-Resistant Systems

If you’re building applications that rely on phone verification:

import hmac
import hashlib
import base64

def verify_call_signature(timestamp, caller_number, signature, shared_secret):
    """Verify STIR/SHAKEN-like signature"""
    message = f"{timestamp}{caller_number}"
    expected = base64.b64encode(
        hmac.new(
            shared_secret.encode(),
            message.encode(),
            hashlib.sha256
        ).digest()
    ).decode()
    return hmac.compare_digest(expected, signature)

Implement proper phone number validation, require multi-factor authentication for phone-based operations, and log all verification attempts for fraud analysis.

Investigating Caller ID Spoofing: Technical Deep Dive

Phone spoofing works at the protocol level. Understanding the mechanics helps identify when it’s happening:

# SS7 (Signaling System 7) - legacy phone network protocol
# Vulnerable to spoofing because it was designed on trust

# When a call comes in, your carrier receives:
# INVITE sip:+15551234567@carrier.com SIP/2.0
# From: "Caller Name" <sip:+15559876543@attacker.com>
# To: <sip:+15551234567@you.com>

# The "From" header contains the spoofed number
# Your phone displays whatever is in the From header
# No verification occurs

# Modern STIR/SHAKEN adds cryptographic signature:
# P-Asserted-Identity: <sip:+15559876543@verified-carrier.com>;alg=RS256;ppt=shaken;iat=timestamp

# This signature proves the calling carrier verified the number
# But only if both carriers support STIR/SHAKEN

Detailed CDR Analysis for Spoofing Detection

Call Detail Records (CDRs) from your carrier can reveal patterns:

#!/usr/bin/env python3
# CDR analysis for spoofing detection

import csv
from datetime import datetime
from collections import defaultdict

def analyze_cdr_for_spoofing(cdr_file):
    """
    Analyze call detail records for spoofing patterns
    CDR format: timestamp, called_number, calling_number, duration, status
    """

    calling_numbers = defaultdict(list)
    suspicious_patterns = []

    with open(cdr_file, 'r') as f:
        reader = csv.DictReader(f)
        for row in reader:
            calling_num = row['calling_number']
            timestamp = datetime.fromisoformat(row['timestamp'])

            calling_numbers[calling_num].append({
                'time': timestamp,
                'duration': int(row['duration']),
                'status': row['status']
            })

    # Pattern 1: Calls from your own number
    if '+1555' + '1234567' in calling_numbers:  # Your number
        suspicious_patterns.append({
            'type': 'Self-call',
            'severity': 'Critical',
            'explanation': 'Calls appearing from your own number'
        })

    # Pattern 2: Geographic impossibilities
    for number, calls in calling_numbers.items():
        for i in range(len(calls) - 1):
            call1 = calls[i]
            call2 = calls[i + 1]

            # Two calls from same number with impossible location distance
            time_diff = (call2['time'] - call1['time']).total_seconds() / 60
            if time_diff < 60:  # Less than 60 minutes
                suspicious_patterns.append({
                    'type': 'Geographic_Impossible',
                    'number': number,
                    'calls': [call1['time'], call2['time']],
                    'explanation': 'Multiple calls in timeframe requiring impossible travel'
                })

    # Pattern 3: Premium rate calls to toll fraud numbers
    premium_destinations = [
        '1900',  # 900 numbers (toll fraud)
        '1976',  # 976 numbers (pay-per-call)
        '1-809', # Caribbean number mills
    ]

    for number, calls in calling_numbers.items():
        for call in calls:
            for premium in premium_destinations:
                if str(call['time']).startswith(premium):
                    suspicious_patterns.append({
                        'type': 'Toll_Fraud',
                        'number': number,
                        'destination': premium,
                        'severity': 'High',
                        'cost_risk': 'High'
                    })

    # Pattern 4: Very short call durations (potential hangup testing)
    for number, calls in calling_numbers.items():
        short_calls = [c for c in calls if c['duration'] < 2]
        if len(short_calls) > 5:
            suspicious_patterns.append({
                'type': 'Hangup_Testing',
                'number': number,
                'short_calls': len(short_calls),
                'explanation': 'Multiple failed/immediate hangup calls (number validation)'
            })

    return suspicious_patterns

# Usage
suspicious = analyze_cdr_for_spoofing('my_cdr.csv')
for pattern in suspicious:
    print(f"Alert: {pattern['type']} - {pattern['explanation']}")

These patterns, combined with CDR data, strongly indicate active spoofing.

SIM Swapping vs Number Spoofing

Important distinction: SIM swapping is different from spoofing:

NUMBER SPOOFING:
- Attacker calls using your number in the CallerID
- Your number isn't compromised
- Your phone isn't affected
- People get calls appearing from you

SIM SWAPPING:
- Attacker claims to be you to carrier
- Carrier moves your number to attacker's SIM
- You lose phone service immediately
- Attacker receives SMS codes for password resets
- Your actual phone number is now hijacked

RESPONSE:
Spoofing: Change Netflix password, add 2FA to email
SIM Swap: Contact carrier immediately, file police report, change ALL passwords, enable account locks

SIM swapping is much more serious and requires immediate carrier intervention.

Carrier Cooperation and Reporting

Your carrier has tools to investigate spoofing:

# Request from your carrier (speak to fraud department):

1. "Please flag my number for anti-spoofing monitoring"
   - Carriers can tag numbers that are being spoofed
   - They monitor and block spoofed calls impersonating you

2. "Provide STIR/SHAKEN authentication status for my line"
   - Is your number STIR/SHAKEN authenticated?
   - Can your calls be spoofed by others?
   - Status codes: A (verified), B (partial), C (unverified)

3. "Generate full origination report for outbound calls"
   - Shows every call claiming to originate from your number
   - Helps identify patterns
   - Can help carrier block spoofing

4. "Enable additional authentication on my account"
   - PIN or security word for account changes
   - Port freeze (prevents number porting to attacker)
   - Call protection service at no cost (depends on carrier)

These steps give carriers ability to protect your number.

Personal Network Notification Protocol

If your number is being spoofed, notify your contacts:

Email Template:

Subject: Security Alert - My Phone Number May Have Been Spoofed

Hi everyone,

I wanted to let you know that my phone number (+1-555-123-4567) may be
being used by scammers to call people without my knowledge or consent.

If you receive a call from my number:
- It may NOT actually be from me
- Be wary of any requests for money, passwords, or personal information
- Contact me through a different method to verify

To verify it's really me:
- Call me back at [alternate number]
- Text me at [Signal/Telegram/other encrypted app]
- Email me

Do NOT:
- Give out personal information to unknown callers
- Click links or download files from unsolicited calls
- Share passwords or verification codes

I apologize for any inconvenience. The carrier is investigating.

Thanks,
[Your name]

Preemptive notification prevents scammers from successfully impersonating you.

For Developers: Phone Verification Best Practices

If you’re implementing phone-based verification:

# Anti-spoofing verification system

import hashlib
import secrets
from datetime import datetime, timedelta

class PhoneVerificationSystem:
    def __init__(self):
        self.verification_attempts = {}
        self.verified_numbers = set()

    def send_verification_code(self, phone_number):
        """
        Send verification code with anti-spoofing measures
        """

        # Check for excessive attempts (sign of attack)
        if phone_number in self.verification_attempts:
            attempts = self.verification_attempts[phone_number]
            if len(attempts) > 5:
                recent = [t for t in attempts if t > datetime.now() - timedelta(hours=1)]
                if len(recent) > 3:
                    raise Exception("Too many verification attempts - account locked")

        # Generate code
        code = secrets.randbelow(1000000)  # 6-digit code
        code_str = f"{code:06d}"

        # Send via SMS
        send_sms(phone_number, f"Your verification code is: {code_str}")

        # Record attempt
        if phone_number not in self.verification_attempts:
            self.verification_attempts[phone_number] = []
        self.verification_attempts[phone_number].append(datetime.now())

        # Store for verification (hashed for security)
        stored_hash = hashlib.sha256(code_str.encode()).hexdigest()
        self.pending_verifications[phone_number] = {
            'code_hash': stored_hash,
            'timestamp': datetime.now(),
            'expires': datetime.now() + timedelta(minutes=10)
        }

    def verify_code(self, phone_number, provided_code):
        """
        Verify the code with anti-spoofing checks
        """

        if phone_number not in self.pending_verifications:
            raise Exception("No pending verification")

        record = self.pending_verifications[phone_number]

        # Check expiration
        if datetime.now() > record['expires']:
            raise Exception("Code expired")

        # Check code (hash comparison to avoid timing attacks)
        provided_hash = hashlib.sha256(provided_code.encode()).hexdigest()
        if secrets.compare_digest(provided_hash, record['code_hash']):
            # Verification successful
            self.verified_numbers.add(phone_number)
            del self.pending_verifications[phone_number]
            return True
        else:
            raise Exception("Invalid code")

This implementation provides rate limiting and secure code verification.

Built by theluckystrike — More at zovo.one