Script Injection Prevention & Detection | Blue Frog Docs

Script Injection Prevention & Detection

Preventing and detecting malicious script injection attacks including XSS and unauthorized third-party scripts

Script Injection Prevention & Detection

What This Means

Script injection is a security vulnerability where attackers insert malicious JavaScript code into your website, either through cross-site scripting (XSS) attacks, compromised third-party scripts, or unauthorized modifications to your codebase. These injected scripts can steal user data, redirect traffic, inject ads, install malware, or compromise your entire website. Prevention and detection are critical for protecting your users and business.

Types of Script Injection

Cross-Site Scripting (XSS):

  • Stored XSS: Malicious script saved in database (comments, user profiles)
  • Reflected XSS: Script in URL parameters reflected back to user
  • DOM-based XSS: Client-side JavaScript manipulates DOM unsafely
  • Mutation XSS (mXSS): Browser parsing creates executable code

Third-Party Script Compromise:

  • CDN compromise (supply chain attack)
  • Compromised analytics/advertising tags
  • Malicious browser extensions
  • Magecart/formjacking attacks
  • Cryptojacking scripts

Server Compromise:

  • Database injection
  • File system modification
  • Admin panel breach
  • Backdoor scripts
  • Web shell injection

Impact on Your Business

Security Risks:

  • User session hijacking
  • Credential theft
  • Payment card data theft (PCI compliance violation)
  • Customer data breach (GDPR violation)
  • Defacement and reputation damage
  • Malware distribution

Business Consequences:

  • Average data breach cost: $4.45M (IBM 2023)
  • PCI fines: $5,000-$100,000/month
  • GDPR fines: Up to €20M or 4% revenue
  • Customer trust loss
  • Revenue loss during incident
  • Legal liability
  • SEO penalties (malware warnings)

User Experience Impact:

  • Redirects to phishing sites
  • Unwanted ads and popups
  • Slow page performance
  • Browser security warnings
  • Loss of user trust

How to Diagnose

Method 1: Content Security Policy (CSP) Violation Reports

Monitor CSP violations:

  1. Check browser console:

    Content Security Policy violation:
    Refused to execute inline script because it violates the following
    Content Security Policy directive: "script-src 'self'"
    
  2. Set up CSP reporting endpoint:

    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self'; script-src 'self' https://trusted-cdn.com; report-uri /csp-report">
    
    // Server endpoint to receive reports
    app.post('/csp-report', (req, res) => {
      const report = req.body;
      console.log('CSP Violation:', report);
    
      // Log to security monitoring
      securityLogger.warn('CSP violation detected', {
        blockedURI: report['csp-report']['blocked-uri'],
        violatedDirective: report['csp-report']['violated-directive'],
        documentURI: report['csp-report']['document-uri']
      });
    
      res.sendStatus(204);
    });
    

What to Look For:

  • Unexpected inline scripts
  • Unauthorized third-party domains
  • Eval() or Function() constructor usage
  • Unknown script sources

Method 2: Subresource Integrity (SRI) Monitoring

Detect modified third-party scripts:

<!-- Script with SRI hash -->
<script src="https://cdn.example.com/library.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

Monitor console for SRI failures:

Failed to find a valid digest in the 'integrity' attribute for resource
'https://cdn.example.com/library.js' with computed SHA-384 integrity...

What to Look For:

  • SRI hash mismatch errors
  • Modified third-party libraries
  • Compromised CDN resources
  • Man-in-the-middle attacks

Method 3: Regular Script Audits

Automated scanning:

# Scan for suspicious patterns in JavaScript
grep -r "eval(" ./public/js/
grep -r "document.write" ./public/js/
grep -r "innerHTML.*=" ./public/js/
grep -r "atob\|btoa" ./public/js/
grep -r "fromCharCode" ./public/js/
grep -r "createElement('script')" ./public/js/

Check for unauthorized scripts:

// List all script tags on page
const scripts = Array.from(document.querySelectorAll('script'));
scripts.forEach(script => {
  console.log({
    src: script.src || '(inline)',
    integrity: script.integrity || '(none)',
    async: script.async,
    defer: script.defer,
    content: script.src ? null : script.textContent.substring(0, 100)
  });
});

What to Look For:

  • Unknown script sources
  • Obfuscated code
  • Base64 encoded scripts
  • Dynamic script injection
  • Suspicious domains

Method 4: Browser DevTools Security Tab

  1. Open Chrome DevTools (F12)
  2. Navigate to "Security" tab
  3. Review security status

What to Look For:

  • Mixed content warnings
  • Certificate issues
  • Insecure origins
  • Security warnings

Method 5: Third-Party Security Scanners

Use automated tools:

  1. Google Safe Browsing:

    https://transparencyreport.google.com/safe-browsing/search?url=yoursite.com
    
  2. Sucuri SiteCheck:

    https://sitecheck.sucuri.net/
    
  3. VirusTotal:

    https://www.virustotal.com/gui/url/yoursite.com
    

What to Look For:

  • Malware detection
  • Blacklist status
  • Suspicious resources
  • Injected content
  • Phishing indicators

General Fixes

Fix 1: Implement Strict Content Security Policy

Block unauthorized scripts:

  1. Basic CSP (start restrictive):

    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self';
                   script-src 'self' https://trusted-cdn.com;
                   style-src 'self' 'unsafe-inline';
                   img-src 'self' data: https:;
                   font-src 'self';
                   connect-src 'self';
                   frame-ancestors 'none';
                   base-uri 'self';
                   form-action 'self';">
    
  2. Nginx configuration:

    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'; base-uri 'self';" always;
    
  3. Apache configuration:

    Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'"
    
  4. Progressive CSP with nonces:

    <!-- Generate random nonce server-side -->
    <?php $nonce = base64_encode(random_bytes(16)); ?>
    
    <meta http-equiv="Content-Security-Policy"
          content="script-src 'nonce-<?php echo $nonce; ?>'">
    
    <!-- Inline scripts require nonce -->
    <script nonce="<?php echo $nonce; ?>">
      console.log('Allowed inline script');
    </script>
    

Fix 2: Sanitize User Input

Prevent XSS through input validation:

  1. Server-side input sanitization:

    // Node.js with DOMPurify
    const createDOMPurify = require('dompurify');
    const { JSDOM } = require('jsdom');
    
    const window = new JSDOM('').window;
    const DOMPurify = createDOMPurify(window);
    
    app.post('/comment', (req, res) => {
      const userComment = req.body.comment;
    
      // Sanitize HTML
      const cleanComment = DOMPurify.sanitize(userComment, {
        ALLOWED_TAGS: ['p', 'br', 'strong', 'em'],
        ALLOWED_ATTR: []
      });
    
      // Save to database
      await db.comments.insert({ comment: cleanComment });
    
      res.json({ success: true });
    });
    
  2. Client-side output encoding:

    // Escape HTML entities
    function escapeHtml(unsafe) {
      return unsafe
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
    }
    
    // Use when displaying user content
    const userInput = '<script>alert("XSS")</script>';
    element.textContent = userInput; // Safe
    // or
    element.innerHTML = escapeHtml(userInput); // Safe
    
  3. Use textContent instead of innerHTML:

    // Unsafe
    element.innerHTML = userInput; ❌
    
    // Safe
    element.textContent = userInput; ✓
    
  4. React automatic escaping:

    // React escapes by default
    function Comment({ text }) {
      return <div>{text}</div>; // Automatically escaped
    }
    
    // Dangerous (avoid)
    function UnsafeComment({ html }) {
      return <div dangerouslySetInnerHTML={{__html: html}} />; ❌
    }
    

Fix 3: Use Subresource Integrity (SRI)

Verify third-party script integrity:

  1. Generate SRI hashes:

    # Generate SHA-384 hash
    curl -s https://cdn.example.com/library.js | \
      openssl dgst -sha384 -binary | \
      openssl base64 -A
    

    Or use online tool: https://www.srihash.org/

  2. Add integrity attribute:

    <script src="https://cdn.example.com/library.js"
            integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
            crossorigin="anonymous"></script>
    
    <link rel="stylesheet"
          href="https://cdn.example.com/styles.css"
          integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
          crossorigin="anonymous">
    
  3. Automated SRI in build tools:

    // webpack.config.js
    const SriPlugin = require('webpack-subresource-integrity');
    
    module.exports = {
      output: {
        crossOriginLoading: 'anonymous'
      },
      plugins: [
        new SriPlugin({
          hashFuncNames: ['sha256', 'sha384'],
          enabled: process.env.NODE_ENV === 'production'
        })
      ]
    };
    

Fix 4: Implement Script Monitoring

Detect unauthorized scripts at runtime:

  1. Monitor new scripts:

    // Detect dynamically added scripts
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (node.tagName === 'SCRIPT') {
            const src = node.src || '(inline)';
    
            // Check against whitelist
            const allowedDomains = [
              'https://www.googletagmanager.com',
              'https://www.google-analytics.com',
              'https://cdn.yoursite.com'
            ];
    
            const isAllowed = allowedDomains.some(domain =>
              src.startsWith(domain)
            ) || src === '(inline)';
    
            if (!isAllowed) {
              console.error('Unauthorized script detected:', src);
              // Remove script
              node.remove();
              // Alert security team
              reportSecurityIncident('unauthorized_script', { src });
            }
          }
        });
      });
    });
    
    observer.observe(document.documentElement, {
      childList: true,
      subtree: true
    });
    
  2. Monitor script execution:

    // Override eval and Function constructor
    (function() {
      const originalEval = window.eval;
      window.eval = function(...args) {
        console.warn('eval() called:', args[0].substring(0, 100));
        reportSecurityIncident('eval_usage', { code: args[0] });
        // Optionally block
        // throw new Error('eval() is not allowed');
        return originalEval.apply(this, args);
      };
    
      const OriginalFunction = window.Function;
      window.Function = function(...args) {
        console.warn('Function constructor called');
        reportSecurityIncident('function_constructor_usage');
        return OriginalFunction.apply(this, args);
      };
    })();
    

Fix 5: Validate and Sanitize URLs

Prevent malicious redirects:

  1. URL validation:

    function isSafeUrl(url) {
      try {
        const parsed = new URL(url, window.location.origin);
    
        // Only allow https and relative URLs
        if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
          return false;
        }
    
        // Block javascript: and data: protocols
        if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {
          return false;
        }
    
        // Whitelist allowed domains
        const allowedDomains = ['yoursite.com', 'trusted-partner.com'];
        const isAllowedDomain = allowedDomains.some(domain =>
          parsed.hostname === domain || parsed.hostname.endsWith(`.${domain}`)
        );
    
        return isAllowedDomain;
      } catch (e) {
        return false;
      }
    }
    
    // Usage
    const redirectUrl = getParameterByName('redirect');
    if (isSafeUrl(redirectUrl)) {
      window.location.href = redirectUrl;
    } else {
      console.error('Unsafe redirect prevented:', redirectUrl);
    }
    
  2. Sanitize href attributes:

    // Check all links
    document.querySelectorAll('a').forEach(link => {
      if (link.href.startsWith('javascript:')) {
        console.error('Malicious link detected:', link.href);
        link.removeAttribute('href');
      }
    });
    

Fix 6: Regular Security Audits

Proactive detection:

  1. Automated daily scans:

    #!/bin/bash
    # security-scan.sh
    
    # Check for suspicious patterns
    find ./public -name "*.js" -exec grep -l "eval(" {} \; > /tmp/eval_usage.txt
    find ./public -name "*.js" -exec grep -l "atob(" {} \; > /tmp/atob_usage.txt
    
    # Compare against baseline
    diff /tmp/eval_usage.txt /var/security/baseline_eval.txt > /tmp/new_eval.txt
    
    if [ -s /tmp/new_eval.txt ]; then
      echo "New eval() usage detected!" | mail -s "Security Alert" security@yoursite.com
    fi
    
    # Scan for known malware signatures
    clamscan -r ./public --infected --log=/var/log/clamav/scan.log
    
  2. Hash verification:

    // Generate checksums of critical files
    const crypto = require('crypto');
    const fs = require('fs');
    
    async function verifyFileIntegrity() {
      const criticalFiles = [
        '/public/js/main.js',
        '/public/js/checkout.js',
        '/public/js/analytics.js'
      ];
    
      const knownHashes = {
        '/public/js/main.js': 'abc123...',
        '/public/js/checkout.js': 'def456...',
        '/public/js/analytics.js': 'ghi789...'
      };
    
      for (const file of criticalFiles) {
        const content = fs.readFileSync(file);
        const hash = crypto.createHash('sha256').update(content).digest('hex');
    
        if (hash !== knownHashes[file]) {
          console.error(`File modified: ${file}`);
          sendSecurityAlert(`Unauthorized modification: ${file}`);
        }
      }
    }
    
    // Run daily
    setInterval(verifyFileIntegrity, 24 * 60 * 60 * 1000);
    

Fix 7: Implement Security Headers

Additional protection layers:

# Nginx configuration
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

# Strict Transport Security
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Or in Apache:

Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "DENY"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

Platform-Specific Guides

Detailed implementation instructions for your specific platform:

Platform Troubleshooting Guide
Shopify Shopify Script Injection Prevention
WordPress WordPress Script Injection Prevention
Wix Wix Script Injection Prevention
Squarespace Squarespace Script Injection Prevention
Webflow Webflow Script Injection Prevention

Verification

After implementing script injection protection:

  1. Test CSP:

    • Try adding inline script (should be blocked)
    • Check console for violations
    • Verify authorized scripts work
  2. Test XSS protection:

    // Try common XSS payloads (in test environment)
    const xssPayloads = [
      '<script>alert("XSS")</script>',
      '<img src=x onerror=alert("XSS")>',
      'javascript:alert("XSS")',
      '<svg onload=alert("XSS")>'
    ];
    
    xssPayloads.forEach(payload => {
      // Verify they don't execute
    });
    
  3. Verify SRI:

    • Modify third-party script
    • Browser should block loading
    • Console shows SRI error
  4. Run security scan:

    • No malware detected
    • No unauthorized scripts
    • All scripts have SRI hashes

Common Mistakes

  1. Too permissive CSP - Allowing 'unsafe-inline' and 'unsafe-eval'
  2. Not sanitizing user input - Trusting client-side validation only
  3. Using innerHTML - Instead of textContent for user content
  4. Missing SRI - Third-party scripts without integrity checks
  5. Not monitoring violations - CSP reports ignored
  6. Trusting all same-origin scripts - Internal compromise possible
  7. Not updating dependencies - Vulnerable libraries
  8. Weak authentication - Admin panels easily compromised
  9. No security audits - Scripts go unmonitored
  10. Ignoring security headers - Missing defense layers

Additional Resources

// SYS.FOOTER