// ============================================================ // PhishGuard AI - content.js // Content script: runs inside every page. // Detects phishing signals and injects feedback banner. // ============================================================ (function() { "use strict"; // ── Page Signal Detection ────────────────────────────────────── function detectPageSignals() { const signals = []; const title = document.title || ""; const bodyText = (document.body?.innerText || "").substring(0, 2000).toLowerCase(); const url = window.location.href.toLowerCase(); // 1. Password form posting to external domain const forms = document.querySelectorAll("form"); forms.forEach(form => { const hasPassword = form.querySelector('input[type="password"]'); const action = (form.getAttribute("action") || "").toLowerCase(); if (hasPassword && action.startsWith("http") && !action.includes(window.location.hostname)) { signals.push("password_form_external_action"); } }); // 2. Brand name in title mismatching hostname const brands = ["paypal","google","apple","microsoft","amazon","netflix", "facebook","instagram","chase","wellsfargo","bankofamerica"]; const hostname = window.location.hostname.toLowerCase(); for (const brand of brands) { if (title.toLowerCase().includes(brand) && !hostname.includes(brand)) { signals.push(`brand_mismatch:${brand}`); } } // 3. Urgency language const urgencyPhrases = [ "your account has been", "verify immediately", "suspended", "unusual activity", "click here now", "act now", "confirm your identity", "limited time", "expires soon" ]; for (const phrase of urgencyPhrases) { if (bodyText.includes(phrase)) { signals.push("urgency_language"); break; } } // 4. Hidden iframes const iframes = document.querySelectorAll("iframe"); iframes.forEach(iframe => { const style = window.getComputedStyle(iframe); const w = parseInt(style.width) || iframe.width; const h = parseInt(style.height) || iframe.height; if (style.display === "none" || style.visibility === "hidden" || (w <= 1 && h <= 1)) { signals.push("hidden_iframe"); } }); return { title, snippet: bodyText.substring(0, 500), signals, }; } // Send signals to background.js try { const pageData = detectPageSignals(); chrome.runtime.sendMessage({ type: "page_signals", url: window.location.href, ...pageData, }); } catch (e) { // Extension context may be invalidated } // ── Feedback Banner Injection ────────────────────────────────── // Listen for messages from background.js to inject banner chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === "inject_feedback_banner") { injectFeedbackBanner(msg.verdict, msg.confidence, msg.urlHash, msg.tier); sendResponse({ success: true }); } }); function injectFeedbackBanner(verdict, confidence, urlHash, tier) { // Don't inject if already present if (document.getElementById("phishguard-feedback-banner")) return; const isPhishing = verdict === "phishing"; const confPct = Math.round(confidence * 100); const tierText = `Tier ${tier}`; const banner = document.createElement("div"); banner.id = "phishguard-feedback-banner"; banner.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; z-index: 2147483647; background: ${isPhishing ? "linear-gradient(135deg, #1a0000, #3a0000)" : "linear-gradient(135deg, #001a00, #003a00)"}; color: white; padding: 10px 20px; display: flex; align-items: center; gap: 12px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 14px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); border-bottom: 2px solid ${isPhishing ? "#ef4444" : "#22c55e"}; `; const icon = isPhishing ? "🛡️" : "✅"; const statusText = isPhishing ? "PhishGuard flagged this page" : "PhishGuard: Page looks safe"; banner.innerHTML = ` ${icon} ${statusText} · ${confPct}% · ${tierText} ${isPhishing ? `` : ""} `; document.body.prepend(banner); document.body.style.marginTop = (banner.offsetHeight) + "px"; // Button handlers document.getElementById("pg-correct")?.addEventListener("click", () => { submitBannerFeedback(urlHash, "correct", banner); }); document.getElementById("pg-wrong")?.addEventListener("click", () => { submitBannerFeedback(urlHash, "incorrect", banner); }); document.getElementById("pg-proceed")?.addEventListener("click", () => { chrome.runtime.sendMessage({ type: "whitelist_url", url: window.location.href }); removeBanner(banner); }); document.getElementById("pg-close")?.addEventListener("click", () => { removeBanner(banner); }); } function submitBannerFeedback(urlHash, feedback, banner) { chrome.runtime.sendMessage({ type: "submit_feedback", url_hash: urlHash, feedback: feedback, }, (response) => { if (response?.success) { banner.innerHTML = ` Thanks! Your feedback helps improve PhishGuard `; setTimeout(() => removeBanner(banner), 3000); } }); } function removeBanner(banner) { document.body.style.marginTop = ""; banner.remove(); } })();