Build a Website Security Scanner Chrome Extension: Complete 2025 Guide

22 min read

Build a Website Security Scanner Chrome Extension: Complete 2025 Guide

Build a Website Security Scanner Chrome Extension: Complete 2025 Guide

Website security is more critical than ever in 2025. With cyberattacks becoming increasingly sophisticated and prevalent, users need powerful tools to protect themselves while browsing the web. A security scanner extension provides an accessible way for users to analyze websites for vulnerabilities directly from their browser, without requiring specialized security knowledge or external tools.

In this comprehensive guide, we’ll walk you through the process of building a fully functional website security scanner Chrome extension from scratch. You’ll learn how to implement vulnerability detection, create an intuitive user interface, and follow best practices for security extension development. Whether you’re a seasoned developer or just starting with Chrome extension development, this guide will equip you with the knowledge to create a powerful security tool.


Why Build a Security Scanner Extension?

The demand for vulnerability checker chrome tools has never been higher. With over 4.5 billion internet users worldwide and cybercriminals becoming more sophisticated, there’s a growing need for accessible security tools that everyday users can leverage without technical expertise.

A site security extension offers several unique advantages over traditional security tools:

  1. Immediate Accessibility: Users can scan any website they’re visiting with a single click
  2. Zero Setup Required: Unlike desktop applications or online scanners, no installation beyond the browser extension is necessary
  3. Context-Aware Analysis: The extension can analyze the current page context, including loaded scripts, forms, and links
  4. Real-Time Feedback: Users receive instant security assessments as they browse

Project Architecture and Prerequisites

Before diving into code, let’s establish the architecture for our security scanner extension. We’ll use Manifest V3, which is the current standard for Chrome extensions and offers improved security and performance.

Required Files Structure

security-scanner/
├── manifest.json
├── popup.html
├── popup.js
├── popup.css
├── content.js
├── background.js
└── icons/
    ├── icon16.png
    ├── icon48.png
    └── icon128.png

Key Features We’ll Implement

Our security scanner extension will include:

  • SSL/TLS Certificate Analysis: Check if websites use secure connections
  • Mixed Content Detection: Identify resources loaded over insecure protocols
  • External Script Tracking: Monitor third-party scripts loaded on the page
  • Form Security Assessment: Analyze forms for secure submission practices
  • Cookie Security Evaluation: Check cookie attributes for security flags
  • CSP Header Analysis: Verify Content Security Policy implementation

Setting Up the Manifest (manifest.json)

The manifest.json file is the backbone of any Chrome extension. Let’s create a comprehensive manifest for our vulnerability checker chrome extension:

{
  "manifest_version": 3,
  "name": "Site Security Scanner",
  "version": "1.0.0",
  "description": "Scan websites for security vulnerabilities, SSL issues, and potential threats",
  "permissions": [
    "activeTab",
    "scripting",
    "storage"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],
  "background": {
    "service_worker": "background.js"
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}

Building the Content Script (content.js)

The content script runs in the context of web pages and collects security-relevant information. This is where the core site security analysis happens:

// content.js - Security Analysis Script

(function() {
  // Store security analysis results
  const securityData = {
    url: window.location.href,
    domain: window.location.hostname,
    ssl: window.location.protocol === 'https:',
    scripts: [],
    forms: [],
    cookies: [],
    mixedContent: false,
    csp: null,
    localStorage: false,
    thirdPartyDomains: new Set()
  };

  // Analyze external scripts
  function analyzeScripts() {
    const scripts = document.querySelectorAll('script[src]');
    scripts.forEach(script => {
      const src = script.src;
      try {
        const url = new URL(src);
        securityData.scripts.push({
          src: src,
          domain: url.hostname,
          isThirdParty: url.hostname !== window.location.hostname
        });
        if (url.hostname !== window.location.hostname) {
          securityData.thirdPartyDomains.add(url.hostname);
        }
      } catch (e) {
        // Invalid URL, skip
      }
    });
  }

  // Check for mixed content (HTTP resources on HTTPS pages)
  function checkMixedContent() {
    const resources = document.querySelectorAll('[src], [href]');
    resources.forEach(resource => {
      const src = resource.src || resource.href;
      if (src && src.startsWith('http:')) {
        securityData.mixedContent = true;
      }
    });
  }

  // Analyze forms for security
  function analyzeForms() {
    const forms = document.querySelectorAll('form');
    forms.forEach(form => {
      const action = form.action || '';
      const method = form.method || 'get';
      const hasPasswordField = form.querySelector('input[type="password"]') !== null;
      
      securityData.forms.push({
        action: action,
        method: method,
        hasPassword: hasPasswordField,
        isSecure: action.startsWith('https:') || action.startsWith('/')
      });
    });
  }

  // Check cookie security
  function analyzeCookies() {
    document.cookie.split(';').forEach(cookie => {
      const [name, value] = cookie.trim().split('=');
      securityData.cookies.push({
        name: name,
        secure: cookie.toLowerCase().includes('secure'),
        httpOnly: cookie.toLowerCase().includes('httponly'),
        sameSite: cookie.toLowerCase().includes('samesite')
      });
    });
  }

  // Check Content Security Policy
  function checkCSP() {
    const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
    if (meta) {
      securityData.csp = meta.getAttribute('content');
    }
  }

  // Check localStorage usage
  function checkLocalStorage() {
    try {
      securityData.localStorage = window.localStorage !== undefined;
    } catch (e) {
      securityData.localStorage = false;
    }
  }

  // Run all analyses
  function runSecurityScan() {
    analyzeScripts();
    checkMixedContent();
    analyzeForms();
    analyzeCookies();
    checkCSP();
    checkLocalStorage();
    
    return securityData;
  }

  // Listen for messages from popup
  chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === 'runScan') {
      const results = runSecurityScan();
      sendResponse(results);
    }
  });
})();

Creating the Background Service Worker (background.js)

The background script handles extension lifecycle events and coordinates communication between the popup and content scripts:

// background.js - Service Worker

// Handle extension installation
chrome.runtime.onInstalled.addListener((details) => {
  console.log('Security Scanner Extension installed:', details.reason);
});

// Handle messages from popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'getSecurityData') {
    // Get the active tab and inject content script
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0]) {
        chrome.tabs.sendMessage(tabs[0].id, { action: 'runScan' }, (response) => {
          sendResponse(response);
        });
      }
    });
    return true; // Keep message channel open for async response
  }
});

Building the Popup Interface (popup.html)

The popup provides the user interface for our vulnerability checker chrome extension:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Site Security Scanner</title>
  <link rel="stylesheet" href="popup.css">
</head>
<body>
  <div class="container">
    <header>
      <h1>🛡️ Security Scanner</h1>
    </header>
    
    <div id="scanning" class="scanning">
      <div class="spinner"></div>
      <p>Scanning website...</p>
    </div>
    
    <div id="results" class="results hidden">
      <div class="score-container">
        <div id="securityScore" class="security-score">--</div>
        <p id="scoreLabel">Security Score</p>
      </div>
      
      <div class="issues-list">
        <div class="issue-category">
          <h3>🔒 Connection Security</h3>
          <ul id="sslResults"></ul>
        </div>
        
        <div class="issue-category">
          <h3>📜 Script Security</h3>
          <ul id="scriptResults"></ul>
        </div>
        
        <div class="issue-category">
          <h3>📝 Form Security</h3>
          <ul id="formResults"></ul>
        </div>
        
        <div class="issue-category">
          <h3>🍪 Cookie Security</h3>
          <ul id="cookieResults"></ul>
        </div>
      </div>
      
      <button id="rescanBtn" class="rescan-btn">🔄 Rescan Website</button>
    </div>
    
    <div id="error" class="error hidden">
      <p>Unable to scan this page. Try refreshing and scanning again.</p>
    </div>
  </div>
  
  <script src="popup.js"></script>
</body>
</html>

Implementing Popup Logic (popup.js)

The popup script handles user interactions and displays security results:

// popup.js - Popup Interaction Logic

document.addEventListener('DOMContentLoaded', () => {
  runSecurityScan();
  
  document.getElementById('rescanBtn').addEventListener('click', runSecurityScan);
});

function runSecurityScan() {
  showScanning();
  
  // Request security data from background script
  chrome.runtime.sendMessage({ action: 'getSecurityData' }, (response) => {
    if (chrome.runtime.lastError || !response) {
      showError();
      return;
    }
    
    displayResults(response);
  });
}

function displayResults(data) {
  const score = calculateSecurityScore(data);
  document.getElementById('securityScore').textContent = score;
  document.getElementById('securityScore').className = `security-score score-${getScoreClass(score)}`;
  
  // Display SSL results
  const sslList = document.getElementById('sslResults');
  sslList.innerHTML = `
    <li class="${data.ssl ? 'safe' : 'warning'}">
      ${data.ssl ? '' : ''} ${data.ssl ? 'Secure HTTPS connection' : 'Insecure HTTP connection'}
    </li>
    <li class="${!data.mixedContent ? 'safe' : 'warning'}">
      ${!data.mixedContent ? '' : ''} ${!data.mixedContent ? 'No mixed content detected' : 'Mixed content detected (HTTP resources on HTTPS page)'}
    </li>
    <li class="${data.csp ? 'safe' : 'info'}">
      ${data.csp ? '' : ''} ${data.csp ? 'CSP header present' : 'No Content Security Policy found'}
    </li>
  `;
  
  // Display script results
  const scriptList = document.getElementById('scriptResults');
  const thirdPartyCount = data.thirdPartyDomains ? data.thirdPartyDomains.size : 0;
  scriptList.innerHTML = `
    <li>Total scripts: ${data.scripts.length}</li>
    <li class="${thirdPartyCount === 0 ? 'safe' : 'warning'}">
      Third-party domains: ${thirdPartyCount}
    </li>
  `;
  
  // Display form results
  const formList = document.getElementById('formResults');
  const insecureForms = data.forms.filter(f => !f.isSecure && f.hasPassword).length;
  formList.innerHTML = `
    <li>Total forms: ${data.forms.length}</li>
    <li class="${insecureForms === 0 ? 'safe' : 'warning'}">
      Forms with insecure action: ${insecureForms}
    </li>
  `;
  
  // Display cookie results
  const cookieList = document.getElementById('cookieResults');
  const secureCookies = data.cookies.filter(c => c.secure).length;
  cookieList.innerHTML = `
    <li>Total cookies: ${data.cookies.length}</li>
    <li class="${secureCookies > 0 ? 'safe' : 'info'}">
      Secure cookies: ${secureCookies}
    </li>
  `;
  
  hideScanning();
  showResults();
}

function calculateSecurityScore(data) {
  let score = 100;
  
  // SSL penalty
  if (!data.ssl) score -= 30;
  
  // Mixed content penalty
  if (data.mixedContent) score -= 20;
  
  // CSP penalty
  if (!data.csp) score -= 15;
  
  // Third-party scripts penalty
  if (data.thirdPartyDomains && data.thirdPartyDomains.size > 5) {
    score -= Math.min(20, data.thirdPartyDomains.size);
  }
  
  // Insecure form penalty
  const insecureForms = data.forms.filter(f => !f.isSecure && f.hasPassword).length;
  score -= insecureForms * 10;
  
  // Cookie penalties
  const nonSecureCookies = data.cookies.filter(c => !c.secure).length;
  score -= Math.min(15, nonSecureCookies * 3);
  
  return Math.max(0, score);
}

function getScoreClass(score) {
  if (score >= 80) return 'good';
  if (score >= 50) return 'medium';
  return 'poor';
}

function showScanning() {
  document.getElementById('scanning').classList.remove('hidden');
  document.getElementById('results').classList.add('hidden');
  document.getElementById('error').classList.add('hidden');
}

function showResults() {
  document.getElementById('scanning').classList.add('hidden');
  document.getElementById('results').classList.remove('hidden');
  document.getElementById('error').classList.add('hidden');
}

function showError() {
  document.getElementById('scanning').classList.add('hidden');
  document.getElementById('results').classList.add('hidden');
  document.getElementById('error').classList.remove('hidden');
}

Styling the Popup (popup.css)

Create an attractive, user-friendly interface for your site security extension:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  width: 350px;
  min-height: 400px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #333;
}

.container {
  padding: 20px;
}

header {
  text-align: center;
  margin-bottom: 20px;
}

header h1 {
  color: white;
  font-size: 1.4rem;
}

.scanning {
  text-align: center;
  padding: 40px 20px;
  color: white;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid rgba(255, 255, 255, 0.3);
  border-top-color: white;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 0 auto 15px;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.results {
  background: white;
  border-radius: 12px;
  padding: 20px;
}

.score-container {
  text-align: center;
  margin-bottom: 20px;
}

.security-score {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  font-weight: bold;
  color: white;
  margin: 0 auto 10px;
}

.score-good { background: #10b981; }
.score-medium { background: #f59e0b; }
.score-poor { background: #ef4444; }

.issues-list {
  margin-bottom: 20px;
}

.issue-category {
  margin-bottom: 15px;
}

.issue-category h3 {
  font-size: 0.9rem;
  margin-bottom: 8px;
  color: #555;
}

.issue-category ul {
  list-style: none;
}

.issue-category li {
  padding: 6px 0;
  font-size: 0.85rem;
  border-bottom: 1px solid #eee;
}

.issue-category li.safe { color: #10b981; }
.issue-category li.warning { color: #f59e0b; }
.issue-category li.info { color: #6b7280; }

.rescan-btn {
  width: 100%;
  padding: 12px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 1rem;
  transition: background 0.2s;
}

.rescan-btn:hover {
  background: #5568d3;
}

.error {
  background: white;
  border-radius: 12px;
  padding: 20px;
  text-align: center;
  color: #ef4444;
}

.hidden {
  display: none;
}

Best Practices for Security Extensions

When building a vulnerability checker chrome extension, follow these essential best practices:

1. Minimize Permissions

Only request the permissions your extension absolutely needs. Excessive permissions raise red flags with users and the Chrome Web Store review team. Our extension uses activeTab and scripting permissions, which are minimal and focused on the specific use case.

2. Implement Proper Input Validation

Never trust data from web pages. Always validate and sanitize any information your extension receives from content scripts before processing or displaying it.

3. Secure Message Passing

Use proper message validation between your content scripts and popup. Verify the origin and structure of all messages to prevent injection attacks.

4. Handle Sensitive Data Carefully

If your extension handles sensitive data, use Chrome’s secure storage APIs and never store unnecessary information. Implement proper encryption for any data that needs to persist.

5. Regular Security Audits

Conduct regular security audits of your extension code. Look for common vulnerabilities like XSS, CSRF, and improper error handling.


Testing Your Extension

Before publishing your security scanner extension, thoroughly test it across different scenarios:

  1. Test on Various Sites: Scan different types of websites (e-commerce, blogs, corporate sites) to ensure comprehensive detection
  2. Edge Cases: Test on pages with no forms, no scripts, or unusual structures
  3. Performance: Ensure the extension doesn’t slow down page loading
  4. Cross-Browser: Test in different Chromium-based browsers

To load your extension in Chrome:

  1. Navigate to chrome://extensions/
  2. Enable “Developer mode” (top right toggle)
  3. Click “Load unpacked” and select your extension folder
  4. Visit any website and click the extension icon to scan

Publishing Your Extension

Once tested, publish your site security extension to the Chrome Web Store:

  1. Create a developer account at the Chrome Web Store
  2. Package your extension as a ZIP file
  3. Upload and fill in the store listing details
  4. Submit for review (typically takes 24-72 hours)

Conclusion

Building a security scanner extension is an excellent project that combines practical utility with technical complexity. By following this guide, you’ve learned how to create a fully functional vulnerability checker that can analyze SSL certificates, detect mixed content, monitor third-party scripts, assess form security, and evaluate cookie attributes.

The demand for vulnerability checker chrome tools continues to grow as users become more security-conscious. Your extension can help millions of users make informed decisions about the websites they visit and the data they share.

Remember to keep your extension updated with new security checks and improvements. Cyber threats evolve constantly, and your security scanner should evolve with them. With the foundation you’ve built in this guide, you’re well-equipped to create a powerful tool that makes the web a safer place for everyone.

Start building your site security scanner today and contribute to a more secure browsing experience for all Chrome users!

No previous article
No next article