Block Phishing Chrome Extension Guide (2026)

Chrome Block Phishing Extension: A Developer Guide to Building Browser-Based Threat Detection

Phishing attacks remain one of the most effective vectors for credential theft and account compromise. For developers and power users, understanding how Chrome block phishing extension technology works provides both practical defensive knowledge and a foundation for building custom security tools. This guide examines the architecture, APIs, and implementation patterns behind browser-based phishing detection.

How Chrome Phishing Protection Works

Chrome’s built-in phishing protection uses Safe Browsing, a Google service that maintains databases of known malicious URLs. When you navigate to a page, Chrome checks the URL against these databases and displays warnings for suspicious sites. Third-party Chrome block phishing extension products extend this functionality with additional detection methods.

The core detection approaches include:

  • URL-based analysis: Checking domains against blocklists and analyzing URL patterns for obfuscation techniques
  • Content inspection: Scanning page content for login forms, credential harvest patterns, and brand impersonation
  • Behavioral analysis: Monitoring for suspicious behaviors like domain spoofing or homograph attacks
  • Machine learning models: Using trained classifiers to identify phishing characteristics

Extension Architecture Patterns

A Chrome block phishing extension typically implements several components working together:

Manifest Configuration

Your extension needs declarative permissions in the manifest:

{
 "manifest_version": 3,
 "name": "PhishGuard",
 "version": "1.0",
 "permissions": [
 "activeTab",
 "storage",
 "tabs"
 ],
 "host_permissions": [
 "<all_urls>"
 ],
 "background": {
 "service_worker": "background.js"
 },
 "content_scripts": [{
 "matches": ["<all_urls>"],
 "js": ["content.js"]
 }]
}

Content Script Detection

The content script analyzes page content for phishing indicators:

// content.js - runs in the context of each page
function detectPhishingIndicators() {
 const indicators = {
 loginForms: document.querySelectorAll('form input[type="password"]').length,
 externalFormActions: 0,
 suspiciousDomains: 0,
 iframeCount: document.querySelectorAll('iframe').length
 };
 
 // Check for password fields outside of known login pages
 const forms = document.querySelectorAll('form');
 forms.forEach(form => {
 const action = form.getAttribute('action');
 if (action && !action.startsWith(window.location.origin)) {
 indicators.externalFormActions++;
 }
 });
 
 // Report findings to background script
 chrome.runtime.sendMessage({
 type: 'PHISHING_ANALYSIS',
 url: window.location.href,
 indicators: indicators
 });
}
// Run detection after page loads
if (document.readyState === 'loading') {
 document.addEventListener('DOMContentLoaded', detectPhishingIndicators);
} else {
 detectPhishingIndicators();
}

Background Service Worker

The background script manages the extension’s core logic:

// background.js
const PHISHING_DATABASE_URL = 'https://your-api.com/phishing-list';
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
 if (message.type === 'PHISHING_ANALYSIS') {
 const score = calculatePhishingScore(message.indicators, message.url);
 
 if (score > 0.7) {
 chrome.tabs.sendMessage(sender.tab.id, {
 type: 'BLOCK_WARNING',
 score: score,
 url: message.url
 });
 }
 sendResponse({ score: score });
 }
 return true;
});
function calculatePhishingScore(indicators, url) {
 let score = 0;
 
 // Weight different indicators
 if (indicators.loginForms > 0) score += 0.3;
 if (indicators.externalFormActions > 0) score += 0.4;
 if (indicators.iframeCount > 2) score += 0.2;
 
 // Check for suspicious URL patterns
 if (url.includes('@')) score += 0.3; // URL with credentials
 if (/[\u0600-\u06FF\u0400-\u04FF]/.test(url)) score += 0.2; // Cyrillic/Arabic
 
 return Math.min(score, 1.0);
}

Practical Detection Techniques

Domain Reputation Checking

Query external APIs for domain reputation data:

async function checkDomainReputation(domain) {
 // Using a hypothetical reputation API
 const response = await fetch(`https://api.example.com/reputation/${domain}`, {
 headers: { 'X-API-Key': 'your-key' }
 });
 
 if (!response.ok) return { suspicious: false };
 
 const data = await response.json();
 return {
 suspicious: data.threat_level > 0.7,
 reasons: data.flags,
 age: data.domain_age_days
 };
}

Visual Similarity Detection

Detect look-alike domains using visual comparison:

function detectHomographAttack(url) {
 const urlObj = new URL(url);
 const hostname = urlObj.hostname;
 
 // Check for mixed scripts (Cyrillic looking like Latin)
 const suspiciousChars = /[\u0430-\u044f\u0410-\u042f]/; // Cyrillic
 const latinChars = /[a-zA-Z]/;
 
 let hasMixedScripts = false;
 let char;
 for (let i = 0; i < hostname.length; i++) {
 char = hostname[i];
 if (suspiciousChars.test(char) && latinChars.test(hostname)) {
 hasMixedScripts = true;
 break;
 }
 }
 
 return hasMixedScripts;
}

Building Custom Detection Rules

For power users, creating custom detection rules involves defining patterns in a rules configuration:

// Custom rules configuration
const customRules = {
 blockedPatterns: [
 /.*-login\..*/i,
 /.*-secure\..*/i,
 /.*-account\..*/i
 ],
 suspiciousTLDs: ['.xyz', '.top', '.click', '.link'],
 brandImpersonation: {
 'google': ['g00gle', 'google-login', 'googIe'],
 'microsoft': ['microsft', 'microsoft-login', 'rnicrosoft'],
 'paypal': ['paypa1', 'paypal-secure', 'paypaI']
 }
};
function evaluateCustomRules(url) {
 const urlObj = new URL(url);
 const findings = [];
 
 // Check blocked patterns
 customRules.blockedPatterns.forEach(pattern => {
 if (pattern.test(url)) {
 findings.push(`URL matches blocked pattern: ${pattern}`);
 }
 });
 
 // Check suspicious TLDs
 if (customRules.suspiciousTLDs.some(tld => urlObj.hostname.endsWith(tld))) {
 findings.push('Domain uses suspicious TLD');
 }
 
 // Check brand impersonation
 const hostnameLower = urlObj.hostname.toLowerCase();
 Object.entries(customRules.brandImpersonation).forEach(([brand, variants]) => {
 variants.forEach(variant => {
 if (hostnameLower.includes(variant)) {
 findings.push(`Possible ${brand} impersonation detected`);
 }
 });
 });
 
 return findings;
}

Deployment Considerations

When deploying a Chrome block phishing extension, consider these factors:

Performance impact: Content scripts run on every page load. Optimize detection logic to complete within 100ms to avoid perceived latency.

Privacy implications: If your extension monitors all URLs, be transparent about data handling. Users increasingly scrutinize extensions with broad permissions.

False positive management: Provide clear user interfaces for reporting false positives. This feedback loop improves detection accuracy over time.

Update frequency: Phishing sites have short lifespans. Your blocklists need regular updates, daily at minimum for high-value targets.

Extension APIs for Advanced Users

Chrome provides several APIs relevant to phishing protection:

  • chrome.safeBrowsing - Direct access to Safe Browsing API
  • chrome.webNavigation - Track navigation events
  • chrome.webRequest - Intercept and analyze network requests
  • chrome.tabs - Access tab information and trigger warnings

Conclusion

Building a Chrome block phishing extension requires understanding browser security APIs, implementing efficient detection algorithms, and balancing protection with user experience. The patterns shown here provide a foundation for creating custom extensions tailored to specific threat models or organizational needs.

For developers, the extension architecture offers a flexible platform for experimenting with detection techniques. For power users, understanding these mechanisms helps evaluate and configure browser security tools effectively.

Step-by-Step: Building the Phishing Blocker

  1. Set up Manifest V3 with declarativeNetRequest, storage, and webNavigation permissions.
  2. Load a block list: download a phishing domain list at install time and store it as a declarativeNetRequest ruleset. Update daily via chrome.alarms.
  3. Check URLs on navigation: use chrome.webNavigation.onBeforeNavigate to intercept navigations and compare hostnames against your block list.
  4. Show a warning page: redirect blocked URLs to an extension-hosted warning page with options to proceed or go back.
  5. Add heuristic checks: check for lookalike domains, excessive subdomain depth, and brand impersonation using JavaScript string analysis.
  6. Handle false positives: add a “This site is safe” button that stores the domain in chrome.storage.local as a user allowlist.

Heuristic URL Analysis

function analyzeUrl(url) {
 const { hostname } = new URL(url);
 const issues = [];
 if (/[^\x00-\x7F]/.test(hostname)) {
 issues.push({ type: 'homograph', severity: 'high' });
 }
 if (hostname.split('.').length > 4) {
 issues.push({ type: 'subdomain_depth', severity: 'medium' });
 }
 const brands = ['paypal', 'amazon', 'apple', 'google', 'microsoft', 'netflix'];
 const cleanHost = hostname.replace(/[0-9]/g, '');
 brands.forEach(brand => {
 if (cleanHost.includes(brand) && !cleanHost.endsWith(brand + '.com')) {
 issues.push({ type: 'brand_impersonation', severity: 'high', brand });
 }
 });
 return issues;
}

Comparison with Existing Protections

Protection Coverage Real-time Privacy Performance
This extension Block list + heuristics Daily Local only Minimal
Chrome Safe Browsing Google database Minutes Partial Minimal
uBlock Origin Multiple lists Hours Local Minimal
Avast Online Security Proprietary Minutes Account Low

Advanced: Safe Browsing API Supplement

async function checkSafeBrowsing(url, apiKey) {
 const resp = await fetch(
 'https://safebrowsing.googleapis.com/v4/threatMatches:find?key=' + apiKey,
 {
 method: 'POST',
 headers: { 'Content-Type': 'application/json' },
 body: JSON.stringify({
 client: { clientId: 'phishing-guard', clientVersion: '1.0' },
 threatInfo: {
 threatTypes: ['MALWARE', 'SOCIAL_ENGINEERING'],
 platformTypes: ['ANY_PLATFORM'],
 threatEntryTypes: ['URL'],
 threatEntries: [{ url }]
 }
 })
 }
 );
 const data = await resp.json();
 return !!(data.matches && data.matches.length > 0);
}

Use this as a secondary check after the local block list.

Troubleshooting

Block list not loading: The rules file must appear in both web_accessible_resources and declarative_net_request.rule_resources in the manifest.

Warning page not showing: webNavigation.onBeforeNavigate cannot cancel navigations. Use declarativeNetRequest rules with a redirect action. this runs at the network level before any content loads.

High false positive rate: Only flag URLs where multiple heuristics trigger simultaneously. A single match is rarely sufficient evidence of a phishing attempt.



I'm a solo developer in Vietnam. 50K Chrome extension users. $500K+ on Upwork. 5 Claude Max subscriptions running agent fleets in parallel. These are my actual CLAUDE.md templates, orchestration configs, and prompts. Not a course. Not theory. The files I copy into every project before I write a line of code. **[See what's inside →](https://zovo.one/lifetime?utm_source=ccg&utm_medium=cta-default&utm_campaign=chrome-block-phishing-extension)** $99 once. Free forever. 47/500 founding spots left.

Related Reading

Built by theluckystrike. More at zovo.one

Find the right skill → Browse 155+ skills in our Skill Finder.