Back to blog
SecurityJanuary 1, 2024ยท 18 min read

Form Security, CSRF Protection, and File Uploads: Protect User Input and Data

A practical Fusebox guide to form security, csrf protection, and file uploads.

Form Security, CSRF Protection, and File Uploads: Protect User Input and Data

Published: January 2024
Reading time: 10 minutes

Forms are the gateway between users and your application. They handle sensitive data, file uploads, and critical actions. Yet they're often the weakest security link. Here's how to analyze form security, detect CSRF vulnerabilities, and validate file upload safety.

Why Form Security Matters

The Attack Surface

  • Every form is a potential SQL injection point
  • CSRF attacks hijack user sessions
  • File uploads can execute malicious code
  • XSS through form inputs affects all users
  • Data leaks through autocomplete and caching

Real Form Security Breaches

British Airways (2018): Payment form skimming, 380,000 cards stolen
Equifax (2017): Form injection led to 147M records breach
Ashley Madison (2015): Weak upload validation exposed all users
GitHub (2014): Form-based XSS gave attackers admin access
PayPal (2016): CSRF vulnerability in money transfer forms

Quick Form Security Analysis

1. Form Security Scanner

// Scan all forms on the page for security issues
(function scanFormSecurity() {
  console.log('๐Ÿ” Form Security Scanner\n');
  
  const forms = document.querySelectorAll('form');
  console.log(`Found ${forms.length} forms on page\n`);
  
  if (forms.length === 0) {
    console.log('No forms detected on this page');
    return;
  }
  
  forms.forEach((form, index) => {
    console.log(`\n๐Ÿ“‹ Form #${index + 1}`);
    console.log('โ”€'.repeat(40));
    
    const formAnalysis = {
      action: form.action || 'current page',
      method: form.method || 'GET',
      secure: true,
      issues: [],
      fields: []
    };
    
    // Basic form attributes
    console.log(`Action: ${formAnalysis.action}`);
    console.log(`Method: ${formAnalysis.method.toUpperCase()}`);
    
    // Check HTTPS
    if (formAnalysis.action.startsWith('http://')) {
      formAnalysis.secure = false;
      formAnalysis.issues.push('Form submits over HTTP!');
      console.log('โŒ Insecure: HTTP submission');
    } else if (window.location.protocol === 'https:' || formAnalysis.action.startsWith('https://')) {
      console.log('โœ… Secure: HTTPS submission');
    }
    
    // Check for CSRF token
    const csrfFields = form.querySelectorAll(
      'input[name*="csrf"], input[name*="token"], input[name*="_token"], input[name*="authenticity"]'
    );
    
    if (csrfFields.length > 0) {
      console.log('โœ… CSRF token found');
      csrfFields.forEach(field => {
        console.log(`  Token field: ${field.name}`);
        if (!field.value) {
          formAnalysis.issues.push('CSRF token is empty');
        }
      });
    } else if (formAnalysis.method.toUpperCase() !== 'GET') {
      console.log('โš ๏ธ No CSRF token detected');
      formAnalysis.issues.push('Missing CSRF protection');
    }
    
    // Analyze form fields
    console.log('\n๐Ÿ” Field Analysis:');
    
    const inputs = form.querySelectorAll('input, textarea, select');
    inputs.forEach(input => {
      const fieldAnalysis = analyzeFormField(input);
      formAnalysis.fields.push(fieldAnalysis);
      
      if (fieldAnalysis.issues.length > 0) {
        console.log(`\n  ${input.name || input.type || 'unnamed field'}:`);
        fieldAnalysis.issues.forEach(issue => {
          console.log(`    โš ๏ธ ${issue}`);
          formAnalysis.issues.push(`${input.name}: ${issue}`);
        });
      }
    });
    
    // Check for file uploads
    const fileInputs = form.querySelectorAll('input[type="file"]');
    if (fileInputs.length > 0) {
      console.log(`\n๐Ÿ“Ž File upload fields: ${fileInputs.length}`);
      fileInputs.forEach(input => {
        analyzeFileUpload(input, formAnalysis);
      });
    }
    
    // Check form validation
    const hasClientValidation = form.hasAttribute('novalidate') === false &&
                              (form.querySelectorAll('[required]').length > 0 ||
                               form.querySelectorAll('[pattern]').length > 0);
    
    console.log(`\nโœ“ Client-side validation: ${hasClientValidation ? 'Yes' : 'No'}`);
    
    if (!hasClientValidation) {
      formAnalysis.issues.push('No client-side validation');
    }
    
    // Security headers check
    if (form.method.toUpperCase() === 'POST') {
      console.log('\n๐Ÿ”’ Security Checks:');
      
      // Check if form has autocomplete off for sensitive fields
      const sensitiveFields = form.querySelectorAll(
        'input[type="password"], input[name*="card"], input[name*="cvv"], input[name*="ssn"]'
      );
      
      sensitiveFields.forEach(field => {
        if (field.autocomplete !== 'off' && field.autocomplete !== 'new-password') {
          console.log(`  โš ๏ธ ${field.name || field.type} allows autocomplete`);
          formAnalysis.issues.push('Sensitive field allows autocomplete');
        }
      });
    }
    
    // Summary
    if (formAnalysis.issues.length > 0) {
      console.log(`\nโŒ Security Issues Found: ${formAnalysis.issues.length}`);
      formAnalysis.issues.slice(0, 5).forEach(issue => {
        console.log(`  โ€ข ${issue}`);
      });
    } else {
      console.log('\nโœ… No major security issues detected');
    }
  });
  
  // Global recommendations
  console.log('\n\n๐Ÿ’ก General Recommendations:');
  console.log('1. Always use HTTPS for form submission');
  console.log('2. Implement CSRF tokens on all state-changing forms');
  console.log('3. Validate input on both client and server');
  console.log('4. Disable autocomplete on sensitive fields');
  console.log('5. Implement proper Content Security Policy');
})();

function analyzeFormField(field) {
  const analysis = {
    name: field.name,
    type: field.type,
    issues: []
  };
  
  // Check password fields
  if (field.type === 'password') {
    if (!field.hasAttribute('minlength') || field.minLength < 8) {
      analysis.issues.push('Weak password requirements');
    }
    if (field.autocomplete !== 'new-password' && field.autocomplete !== 'off') {
      analysis.issues.push('Password field allows autocomplete');
    }
  }
  
  // Check email fields
  if (field.type === 'email') {
    if (!field.hasAttribute('pattern') && !field.hasAttribute('required')) {
      analysis.issues.push('No email validation');
    }
  }
  
  // Check for SQL injection prone names
  const dangerousNames = ['id', 'user_id', 'order', 'sort', 'limit'];
  if (dangerousNames.includes(field.name?.toLowerCase())) {
    analysis.issues.push('Field name prone to SQL injection');
  }
  
  // Check for missing max length
  if ((field.type === 'text' || field.type === 'textarea') && !field.hasAttribute('maxlength')) {
    analysis.issues.push('No maximum length limit');
  }
  
  // Check credit card fields
  if (field.name?.toLowerCase().includes('card') || field.name?.toLowerCase().includes('credit')) {
    if (field.autocomplete !== 'off') {
      analysis.issues.push('Credit card field allows autocomplete');
    }
    if (!field.hasAttribute('pattern')) {
      analysis.issues.push('No credit card format validation');
    }
  }
  
  return analysis;
}

function analyzeFileUpload(input, formAnalysis) {
  console.log(`\n  ๐Ÿ“ File upload: ${input.name || 'unnamed'}`);
  
  // Check accept attribute
  if (input.hasAttribute('accept')) {
    console.log(`    Accept: ${input.accept}`);
    
    // Check for dangerous file types
    const dangerous = ['.exe', '.bat', '.cmd', '.com', '.pif', '.scr', '.vbs', '.js'];
    const accepts = input.accept.toLowerCase();
    
    if (accepts === '*' || accepts === '*/*') {
      console.log('    โš ๏ธ Accepts all file types!');
      formAnalysis.issues.push('File upload accepts dangerous types');
    }
  } else {
    console.log('    โš ๏ธ No file type restrictions');
    formAnalysis.issues.push('File upload has no type restrictions');
  }
  
  // Check for multiple files
  if (input.hasAttribute('multiple')) {
    console.log('    โ„น๏ธ Multiple file upload enabled');
  }
  
  // Check max file size (would need server-side validation)
  console.log('    โš ๏ธ File size limit must be validated server-side');
}

2. CSRF Protection Analyzer

// Analyze CSRF protection mechanisms
function analyzeCSRFProtection() {
  console.log('\n๐Ÿ›ก๏ธ CSRF Protection Analysis\n');
  
  const csrfAnalysis = {
    protected: false,
    mechanisms: [],
    vulnerableForms: [],
    recommendations: []
  };
  
  // 1. Check for CSRF tokens in forms
  console.log('1๏ธโƒฃ Checking CSRF Tokens:');
  
  const forms = document.querySelectorAll('form');
  let protectedForms = 0;
  
  forms.forEach((form, index) => {
    const method = form.method.toUpperCase() || 'GET';
    
    if (method !== 'GET') {
      const csrfToken = form.querySelector(
        'input[name*="csrf"], input[name*="token"], input[name*="_token"], input[name*="authenticity"], meta[name="csrf-token"]'
      );
      
      if (csrfToken) {
        protectedForms++;
        console.log(`  โœ… Form #${index + 1}: CSRF token present`);
      } else {
        csrfAnalysis.vulnerableForms.push({
          index: index + 1,
          action: form.action || 'current page',
          method: method
        });
        console.log(`  โŒ Form #${index + 1}: No CSRF token (${method} ${form.action || '/'})`);
      }
    }
  });
  
  if (protectedForms > 0) {
    csrfAnalysis.protected = true;
    csrfAnalysis.mechanisms.push('CSRF tokens');
  }
  
  // 2. Check meta tags for CSRF tokens
  console.log('\n2๏ธโƒฃ Checking Meta Tags:');
  
  const csrfMeta = document.querySelector('meta[name="csrf-token"], meta[name="_csrf"]');
  if (csrfMeta) {
    console.log(`  โœ… CSRF meta tag found: ${csrfMeta.name}`);
    console.log(`  Token: ${csrfMeta.content.substring(0, 20)}...`);
    csrfAnalysis.mechanisms.push('Meta tag token');
    
    // Check if token is being used in AJAX
    checkAjaxCSRF();
  } else {
    console.log('  โŒ No CSRF meta tag found');
  }
  
  // 3. Check cookies for SameSite attribute
  console.log('\n3๏ธโƒฃ Checking Cookie Security:');
  
  // We can't read HttpOnly cookies, but we can check what we can see
  const cookies = document.cookie.split(';');
  
  if (cookies.length > 0) {
    console.log(`  Visible cookies: ${cookies.length}`);
    console.log('  โš ๏ธ Note: HttpOnly cookies not visible to JavaScript');
    console.log('  โ„น๏ธ SameSite attribute must be checked server-side');
    
    // Check for session cookies
    const sessionCookies = cookies.filter(c => 
      c.includes('session') || c.includes('SESS') || c.includes('sid')
    );
    
    if (sessionCookies.length > 0) {
      console.log(`  ๐Ÿช Session cookies found: ${sessionCookies.length}`);
      csrfAnalysis.recommendations.push('Ensure session cookies use SameSite=Strict or Lax');
    }
  }
  
  // 4. Check for double submit cookie pattern
  console.log('\n4๏ธโƒฃ Checking Double Submit Pattern:');
  
  const tokenInCookie = cookies.some(c => c.includes('csrf') || c.includes('xsrf'));
  const tokenInForm = document.querySelector('input[name*="csrf"]');
  
  if (tokenInCookie && tokenInForm) {
    console.log('  โœ… Double submit cookie pattern detected');
    csrfAnalysis.mechanisms.push('Double submit cookies');
  } else {
    console.log('  โŒ No double submit pattern found');
  }
  
  // 5. Check custom headers (for AJAX)
  console.log('\n5๏ธโƒฃ Checking Custom Headers:');
  
  // Override XMLHttpRequest to check for custom headers
  const originalOpen = XMLHttpRequest.prototype.open;
  const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
  let customHeadersFound = false;
  
  XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
    if (header.toLowerCase().includes('csrf') || header.toLowerCase().includes('xsrf')) {
      customHeadersFound = true;
      console.log(`  โœ… Custom header detected: ${header}`);
      csrfAnalysis.mechanisms.push('Custom headers');
    }
    return originalSetRequestHeader.apply(this, arguments);
  };
  
  // 6. Check Origin/Referer validation
  console.log('\n6๏ธโƒฃ Origin Validation:');
  console.log('  โ„น๏ธ Origin/Referer validation happens server-side');
  console.log('  โ„น๏ธ Cannot be verified from client-side');
  
  // Summary
  console.log('\n๐Ÿ“Š CSRF Protection Summary:');
  console.log(`Protected mechanisms found: ${csrfAnalysis.mechanisms.length}`);
  
  if (csrfAnalysis.mechanisms.length > 0) {
    console.log('\nActive protections:');
    csrfAnalysis.mechanisms.forEach(mechanism => {
      console.log(`  โ€ข ${mechanism}`);
    });
  }
  
  if (csrfAnalysis.vulnerableForms.length > 0) {
    console.log('\nโŒ Vulnerable forms:');
    csrfAnalysis.vulnerableForms.forEach(form => {
      console.log(`  โ€ข Form #${form.index}: ${form.method} ${form.action}`);
    });
  }
  
  // Recommendations
  console.log('\n๐Ÿ’ก CSRF Protection Recommendations:');
  console.log('1. Use anti-CSRF tokens on all state-changing operations');
  console.log('2. Implement SameSite cookie attribute (Strict or Lax)');
  console.log('3. Verify Origin/Referer headers server-side');
  console.log('4. Use custom headers for AJAX requests');
  console.log('5. Require re-authentication for sensitive actions');
  
  if (csrfAnalysis.recommendations.length > 0) {
    console.log('\nSpecific recommendations:');
    csrfAnalysis.recommendations.forEach(rec => {
      console.log(`  โ€ข ${rec}`);
    });
  }
  
  return csrfAnalysis;
}

function checkAjaxCSRF() {
  // Check if popular frameworks are setting CSRF headers
  
  // jQuery
  if (window.jQuery) {
    console.log('  ๐Ÿ“ฆ jQuery detected - checking CSRF setup...');
    
    // Check if ajaxSetup includes CSRF
    if (window.jQuery.ajaxSetup) {
      console.log('    โ„น๏ธ Check $.ajaxSetup() for CSRF headers');
    }
  }
  
  // Axios
  if (window.axios) {
    console.log('  ๐Ÿ“ฆ Axios detected - checking CSRF setup...');
    console.log('    โ„น๏ธ Check axios.defaults.headers for CSRF');
  }
  
  // Fetch wrapper
  const originalFetch = window.fetch;
  let csrfHeaderInFetch = false;
  
  window.fetch = function(...args) {
    if (args[1] && args[1].headers) {
      Object.keys(args[1].headers).forEach(header => {
        if (header.toLowerCase().includes('csrf') || header.toLowerCase().includes('xsrf')) {
          csrfHeaderInFetch = true;
        }
      });
    }
    return originalFetch.apply(this, args);
  };
  
  if (csrfHeaderInFetch) {
    console.log('  โœ… CSRF headers detected in fetch requests');
  }
}

analyzeCSRFProtection();

3. File Upload Security Scanner

// Analyze file upload security
function analyzeFileUploadSecurity() {
  console.log('\n๐Ÿ“Ž File Upload Security Analysis\n');
  
  const fileInputs = document.querySelectorAll('input[type="file"]');
  
  if (fileInputs.length === 0) {
    console.log('No file upload inputs found on this page');
    return;
  }
  
  console.log(`Found ${fileInputs.length} file upload inputs\n`);
  
  fileInputs.forEach((input, index) => {
    console.log(`\n๐Ÿ“ File Upload #${index + 1}`);
    console.log('โ”€'.repeat(40));
    
    const uploadAnalysis = {
      name: input.name || 'unnamed',
      secure: true,
      issues: [],
      features: []
    };
    
    console.log(`Field name: ${uploadAnalysis.name}`);
    
    // 1. Check accept attribute
    if (input.hasAttribute('accept')) {
      const accept = input.accept.toLowerCase();
      console.log(`\nโœ… File type restrictions: ${accept}`);
      
      // Check for dangerous patterns
      if (accept === '*/*' || accept === '.*') {
        uploadAnalysis.issues.push('Accepts all file types');
        console.log('  โš ๏ธ Warning: Accepts any file type!');
      } else {
        // Check for executable types
        const dangerous = ['.exe', '.bat', '.sh', '.cmd', '.com', '.scr', '.vbs', '.js', '.jar'];
        const risky = dangerous.filter(ext => accept.includes(ext));
        
        if (risky.length > 0) {
          uploadAnalysis.issues.push(`Accepts dangerous types: ${risky.join(', ')}`);
          console.log(`  โŒ Dangerous types allowed: ${risky.join(', ')}`);
        } else {
          uploadAnalysis.features.push('Safe file types only');
        }
      }
    } else {
      uploadAnalysis.issues.push('No file type restrictions');
      console.log('\nโŒ No accept attribute - accepts all file types');
    }
    
    // 2. Check multiple files
    if (input.hasAttribute('multiple')) {
      console.log('\n๐Ÿ“š Multiple file upload enabled');
      uploadAnalysis.features.push('Multiple files allowed');
      
      // This could be a DoS vector
      uploadAnalysis.issues.push('Multiple files could cause DoS');
    }
    
    // 3. Check for client-side validation
    const form = input.closest('form');
    if (form) {
      const hasValidation = form.querySelector('.file-validation, .file-size-limit, [data-max-size]');
      
      if (hasValidation) {
        console.log('\nโœ… Client-side validation detected');
        uploadAnalysis.features.push('Client-side validation');
      } else {
        console.log('\nโš ๏ธ No client-side validation detected');
      }
    }
    
    // 4. Check for preview functionality (potential XSS)
    const previewElements = document.querySelectorAll(
      `[data-preview*="${input.name}"], #${input.id}-preview, .file-preview`
    );
    
    if (previewElements.length > 0) {
      console.log('\n๐Ÿ–ผ๏ธ File preview functionality detected');
      uploadAnalysis.issues.push('File preview could lead to XSS');
      console.log('  โš ๏ธ Ensure previews are safely sandboxed');
    }
    
    // 5. Security recommendations
    console.log('\n๐Ÿ”’ Security Checks Required (Server-side):');
    console.log('  โ€ข File size limits');
    console.log('  โ€ข File type validation (MIME type + magic numbers)');
    console.log('  โ€ข Filename sanitization');
    console.log('  โ€ข Virus scanning');
    console.log('  โ€ข Store outside web root');
    console.log('  โ€ข Generate new filenames');
    console.log('  โ€ข Serve through separate domain');
    
    // 6. Check for drag-and-drop
    const dropZones = document.querySelectorAll('[ondrop], [data-drop-zone], .drop-zone, .dropzone');
    if (dropZones.length > 0) {
      console.log('\n๐ŸŽฏ Drag-and-drop upload detected');
      uploadAnalysis.features.push('Drag-and-drop support');
    }
    
    // Summary
    if (uploadAnalysis.issues.length > 0) {
      console.log(`\nโŒ Security Issues: ${uploadAnalysis.issues.length}`);
      uploadAnalysis.issues.forEach(issue => {
        console.log(`  โ€ข ${issue}`);
      });
    }
    
    if (uploadAnalysis.features.length > 0) {
      console.log(`\nโœ… Features: ${uploadAnalysis.features.length}`);
      uploadAnalysis.features.forEach(feature => {
        console.log(`  โ€ข ${feature}`);
      });
    }
  });
  
  // Check for chunked upload libraries
  console.log('\n\n๐Ÿ” Advanced Upload Detection:');
  
  const uploadLibraries = {
    'dropzone': window.Dropzone,
    'uppy': window.Uppy,
    'filepond': window.FilePond,
    'resumable': window.Resumable,
    'plupload': window.plupload
  };
  
  Object.entries(uploadLibraries).forEach(([name, lib]) => {
    if (lib) {
      console.log(`  โœ… ${name} library detected`);
    }
  });
  
  // Global recommendations
  console.log('\n๐Ÿ’ก File Upload Security Best Practices:');
  console.log('1. Validate file type by magic numbers, not extension');
  console.log('2. Implement strict file size limits');
  console.log('3. Generate new random filenames');
  console.log('4. Store uploads outside document root');
  console.log('5. Serve files from a separate domain');
  console.log('6. Scan uploads for malware');
  console.log('7. Use Content-Disposition header for downloads');
  console.log('8. Implement rate limiting on uploads');
}

analyzeFileUploadSecurity();

Advanced Security Analysis

1. XSS Prevention in Forms

// Check for XSS vulnerabilities in forms
function analyzeFormXSS() {
  console.log('\n๐Ÿ›ก๏ธ Form XSS Prevention Analysis\n');
  
  const xssAnalysis = {
    vulnerableFields: [],
    protections: [],
    score: 100
  };
  
  // 1. Check input sanitization
  console.log('1๏ธโƒฃ Input Sanitization:');
  
  const inputs = document.querySelectorAll('input[type="text"], textarea');
  
  inputs.forEach(input => {
    // Check for dangerous event handlers
    const dangerousAttrs = ['onerror', 'onload', 'onclick', 'onmouseover'];
    let hasEventHandler = false;
    
    dangerousAttrs.forEach(attr => {
      if (input.hasAttribute(attr)) {
        hasEventHandler = true;
        xssAnalysis.vulnerableFields.push({
          field: input.name || input.id,
          issue: `Has ${attr} handler`
        });
      }
    });
    
    // Check for lack of encoding
    if (input.value && input.value.includes('<script>')) {
      xssAnalysis.vulnerableFields.push({
        field: input.name || input.id,
        issue: 'Contains unencoded script tags'
      });
    }
  });
  
  // 2. Check output encoding
  console.log('\n2๏ธโƒฃ Output Encoding:');
  
  // Look for places where form data might be displayed
  const outputElements = document.querySelectorAll('[data-bind], [ng-bind-html], .user-content');
  
  if (outputElements.length > 0) {
    console.log(`  Found ${outputElements.length} elements that may display user content`);
    console.log('  โš ๏ธ Ensure proper output encoding is applied');
  }
  
  // 3. Check Content Security Policy
  console.log('\n3๏ธโƒฃ Content Security Policy:');
  
  const cspMeta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
  
  if (cspMeta) {
    const csp = cspMeta.content;
    console.log('  โœ… CSP found');
    
    if (csp.includes("'unsafe-inline'")) {
      console.log('  โš ๏ธ CSP allows unsafe-inline scripts');
      xssAnalysis.score -= 20;
    }
    
    if (csp.includes("'unsafe-eval'")) {
      console.log('  โš ๏ธ CSP allows eval()');
      xssAnalysis.score -= 10;
    }
    
    xssAnalysis.protections.push('Content Security Policy');
  } else {
    console.log('  โŒ No CSP meta tag found');
    xssAnalysis.score -= 25;
  }
  
  // 4. Check framework protections
  console.log('\n4๏ธโƒฃ Framework XSS Protection:');
  
  // React
  if (window.React) {
    console.log('  โœ… React detected - automatic XSS protection');
    xssAnalysis.protections.push('React XSS protection');
  }
  
  // Angular
  if (window.angular || document.querySelector('[ng-app]')) {
    console.log('  โœ… Angular detected - built-in sanitization');
    xssAnalysis.protections.push('Angular sanitization');
  }
  
  // Vue
  if (window.Vue) {
    console.log('  โœ… Vue detected - automatic escaping');
    xssAnalysis.protections.push('Vue XSS protection');
  }
  
  // 5. Check validation patterns
  console.log('\n5๏ธโƒฃ Input Validation:');
  
  const validatedInputs = document.querySelectorAll('input[pattern], input[type="email"], input[type="url"]');
  
  if (validatedInputs.length > 0) {
    console.log(`  โœ… ${validatedInputs.length} inputs have validation patterns`);
    xssAnalysis.protections.push('Input validation patterns');
  } else {
    console.log('  โš ๏ธ No input validation patterns found');
  }
  
  // Summary
  console.log('\n๐Ÿ“Š XSS Protection Score:', xssAnalysis.score + '/100');
  
  if (xssAnalysis.vulnerableFields.length > 0) {
    console.log('\nโŒ Vulnerable Fields:');
    xssAnalysis.vulnerableFields.forEach(vuln => {
      console.log(`  โ€ข ${vuln.field}: ${vuln.issue}`);
    });
  }
  
  if (xssAnalysis.protections.length > 0) {
    console.log('\nโœ… Active Protections:');
    xssAnalysis.protections.forEach(protection => {
      console.log(`  โ€ข ${protection}`);
    });
  }
  
  console.log('\n๐Ÿ’ก XSS Prevention Recommendations:');
  console.log('1. Encode all user input before display');
  console.log('2. Use framework auto-escaping features');
  console.log('3. Implement strict Content Security Policy');
  console.log('4. Validate input on client and server');
  console.log('5. Use textContent instead of innerHTML');
  console.log('6. Sanitize HTML if rich text is needed');
  
  return xssAnalysis;
}

analyzeFormXSS();

2. Form Data Leakage Detection

// Detect potential data leakage in forms
function detectFormDataLeakage() {
  console.log('\n๐Ÿ” Form Data Leakage Detection\n');
  
  const leakageRisks = {
    autocomplete: [],
    localStorage: [],
    urlLeaks: [],
    caching: []
  };
  
  // 1. Check autocomplete on sensitive fields
  console.log('1๏ธโƒฃ Autocomplete on Sensitive Fields:');
  
  const sensitiveSelectors = [
    'input[type="password"]',
    'input[name*="ssn"]',
    'input[name*="social"]',
    'input[name*="card"]',
    'input[name*="cvv"]',
    'input[name*="cvc"]',
    'input[name*="pin"]',
    'input[name*="account"]',
    'input[name*="routing"]'
  ];
  
  sensitiveSelectors.forEach(selector => {
    const fields = document.querySelectorAll(selector);
    fields.forEach(field => {
      if (field.autocomplete !== 'off' && field.autocomplete !== 'new-password') {
        leakageRisks.autocomplete.push({
          field: field.name || field.type,
          risk: 'Autocomplete enabled on sensitive field'
        });
        console.log(`  โŒ ${field.name || field.type}: Autocomplete not disabled`);
      }
    });
  });
  
  if (leakageRisks.autocomplete.length === 0) {
    console.log('  โœ… All sensitive fields have autocomplete disabled');
  }
  
  // 2. Check GET method forms
  console.log('\n2๏ธโƒฃ GET Method Forms (URL exposure):');
  
  const getForms = document.querySelectorAll('form[method="get"], form:not([method])');
  getForms.forEach((form, index) => {
    const hasPassword = form.querySelector('input[type="password"]');
    const hasSensitive = form.querySelector(sensitiveSelectors.join(','));
    
    if (hasPassword || hasSensitive) {
      leakageRisks.urlLeaks.push({
        form: `Form #${index + 1}`,
        risk: 'Sensitive data in GET request'
      });
      console.log(`  โŒ Form #${index + 1} uses GET with sensitive fields`);
    }
  });
  
  if (leakageRisks.urlLeaks.length === 0 && getForms.length > 0) {
    console.log('  โœ… No sensitive data in GET forms');
  }
  
  // 3. Check localStorage/sessionStorage usage
  console.log('\n3๏ธโƒฃ Browser Storage:');
  
  // Check for form data in storage
  const storageKeys = [];
  
  for (let i = 0; i < localStorage.length; i++) {
    const key = localStorage.key(i);
    if (key.includes('form') || key.includes('input') || key.includes('field')) {
      storageKeys.push({ storage: 'localStorage', key });
    }
  }
  
  for (let i = 0; i < sessionStorage.length; i++) {
    const key = sessionStorage.key(i);
    if (key.includes('form') || key.includes('input') || key.includes('field')) {
      storageKeys.push({ storage: 'sessionStorage', key });
    }
  }
  
  if (storageKeys.length > 0) {
    console.log(`  โš ๏ธ Form data found in browser storage:`);
    storageKeys.forEach(item => {
      console.log(`    โ€ข ${item.storage}: ${item.key}`);
      leakageRisks.localStorage.push(item);
    });
  } else {
    console.log('  โœ… No form data found in browser storage');
  }
  
  // 4. Check caching headers
  console.log('\n4๏ธโƒฃ Form Page Caching:');
  
  // Check if page with forms has no-cache headers
  const hasForms = document.querySelectorAll('form').length > 0;
  
  if (hasForms) {
    console.log('  โš ๏ธ Page contains forms - ensure proper cache headers:');
    console.log('    โ€ข Cache-Control: no-store, no-cache');
    console.log('    โ€ข Pragma: no-cache');
    
    // Check meta tags
    const noCache = document.querySelector('meta[http-equiv="cache-control"]');
    if (noCache && noCache.content.includes('no-cache')) {
      console.log('  โœ… No-cache meta tag found');
    } else {
      leakageRisks.caching.push('Form page may be cached');
    }
  }
  
  // 5. Check for form data in URLs
  console.log('\n5๏ธโƒฃ URL Parameter Leakage:');
  
  const urlParams = new URLSearchParams(window.location.search);
  const suspiciousParams = [];
  
  for (let [key, value] of urlParams) {
    if (key.match(/pass|pwd|ssn|card|cvv|pin|account/i)) {
      suspiciousParams.push(key);
    }
  }
  
  if (suspiciousParams.length > 0) {
    console.log(`  โŒ Sensitive parameters in URL: ${suspiciousParams.join(', ')}`);
    leakageRisks.urlLeaks.push({
      risk: 'Sensitive data in current URL',
      params: suspiciousParams
    });
  } else {
    console.log('  โœ… No sensitive data in URL');
  }
  
  // Summary
  const totalRisks = Object.values(leakageRisks).flat().length;
  
  console.log(`\n๐Ÿ“Š Data Leakage Summary: ${totalRisks} risks found`);
  
  if (totalRisks > 0) {
    console.log('\nโŒ Leakage Risks:');
    Object.entries(leakageRisks).forEach(([category, risks]) => {
      if (risks.length > 0) {
        console.log(`\n${category}:`);
        risks.forEach(risk => {
          console.log(`  โ€ข ${risk.risk || risk.field}`);
        });
      }
    });
  }
  
  console.log('\n๐Ÿ’ก Data Leakage Prevention:');
  console.log('1. Use POST for all sensitive data');
  console.log('2. Set autocomplete="off" on sensitive fields');
  console.log('3. Add no-cache headers to form pages');
  console.log('4. Clear form data from storage after submission');
  console.log('5. Never put sensitive data in URLs');
  console.log('6. Use HTTPS to prevent network sniffing');
  
  return leakageRisks;
}

detectFormDataLeakage();

Complete Form Security Audit

Comprehensive Form Security Assessment

// Run complete form security audit
async function completeFormSecurityAudit() {
  console.log('๐Ÿ” COMPLETE FORM SECURITY AUDIT');
  console.log('โ•'.repeat(50));
  console.log(`URL: ${window.location.href}`);
  console.log(`Date: ${new Date().toLocaleDateString()}\n`);
  
  const audit = {
    score: 100,
    forms: [],
    csrfProtection: false,
    httpsOnly: window.location.protocol === 'https:',
    xssProtection: false,
    fileUploadRisks: [],
    dataLeakage: [],
    recommendations: []
  };
  
  // Phase 1: Form Discovery
  console.log('๐Ÿ“‹ PHASE 1: FORM DISCOVERY');
  console.log('โ”€'.repeat(40));
  
  const forms = document.querySelectorAll('form');
  console.log(`Forms found: ${forms.length}`);
  
  if (forms.length === 0) {
    console.log('No forms on this page');
    return audit;
  }
  
  // Analyze each form
  forms.forEach((form, index) => {
    const formAnalysis = {
      index: index + 1,
      action: form.action || window.location.href,
      method: form.method.toUpperCase() || 'GET',
      secure: true,
      issues: []
    };
    
    // Check HTTPS
    if (formAnalysis.action.startsWith('http://')) {
      formAnalysis.secure = false;
      formAnalysis.issues.push('Submits over HTTP');
      audit.score -= 20;
    }
    
    // Check CSRF
    const csrfToken = form.querySelector('[name*="csrf"], [name*="token"]');
    if (formAnalysis.method === 'POST' && !csrfToken) {
      formAnalysis.issues.push('No CSRF token');
      audit.score -= 10;
    } else if (csrfToken) {
      audit.csrfProtection = true;
    }
    
    audit.forms.push(formAnalysis);
  });
  
  // Phase 2: CSRF Analysis
  console.log('\n๐Ÿ›ก๏ธ PHASE 2: CSRF PROTECTION');
  console.log('โ”€'.repeat(40));
  
  const csrfMeta = document.querySelector('meta[name="csrf-token"]');
  if (csrfMeta || audit.csrfProtection) {
    console.log('โœ… CSRF protection detected');
  } else {
    console.log('โŒ No CSRF protection found');
    audit.score -= 15;
    audit.recommendations.push('Implement CSRF tokens');
  }
  
  // Phase 3: XSS Prevention
  console.log('\n๐Ÿšซ PHASE 3: XSS PREVENTION');
  console.log('โ”€'.repeat(40));
  
  const csp = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
  
  if (csp) {
    console.log('โœ… Content Security Policy found');
    audit.xssProtection = true;
  } else {
    console.log('โŒ No CSP found');
    audit.score -= 10;
    audit.recommendations.push('Implement Content Security Policy');
  }
  
  // Check for dangerous patterns
  const dangerousInputs = document.querySelectorAll('input[onchange], input[onclick], textarea[onchange]');
  if (dangerousInputs.length > 0) {
    console.log(`โš ๏ธ ${dangerousInputs.length} inputs with inline event handlers`);
    audit.score -= 5;
  }
  
  // Phase 4: File Upload Security
  console.log('\n๐Ÿ“Ž PHASE 4: FILE UPLOAD SECURITY');
  console.log('โ”€'.repeat(40));
  
  const fileInputs = document.querySelectorAll('input[type="file"]');
  
  if (fileInputs.length > 0) {
    console.log(`File uploads: ${fileInputs.length}`);
    
    fileInputs.forEach(input => {
      if (!input.accept || input.accept === '*/*') {
        audit.fileUploadRisks.push('Unrestricted file types');
        audit.score -= 10;
      }
    });
  } else {
    console.log('No file uploads found');
  }
  
  // Phase 5: Data Leakage
  console.log('\n๐Ÿ’ง PHASE 5: DATA LEAKAGE CHECK');
  console.log('โ”€'.repeat(40));
  
  // Check sensitive fields
  const passwordFields = document.querySelectorAll('input[type="password"]');
  const sensitiveFields = document.querySelectorAll('input[name*="card"], input[name*="ssn"]');
  
  // Check autocomplete
  let autocompleteIssues = 0;
  [...passwordFields, ...sensitiveFields].forEach(field => {
    if (field.autocomplete !== 'off') {
      autocompleteIssues++;
    }
  });
  
  if (autocompleteIssues > 0) {
    console.log(`โŒ ${autocompleteIssues} sensitive fields allow autocomplete`);
    audit.dataLeakage.push('Autocomplete on sensitive fields');
    audit.score -= 10;
  } else if (passwordFields.length > 0 || sensitiveFields.length > 0) {
    console.log('โœ… Sensitive fields have autocomplete disabled');
  }
  
  // Check GET forms with sensitive data
  const getForms = Array.from(forms).filter(f => 
    (f.method || 'GET').toUpperCase() === 'GET'
  );
  
  getForms.forEach(form => {
    if (form.querySelector('input[type="password"], input[name*="card"]')) {
      audit.dataLeakage.push('Sensitive data in GET request');
      audit.score -= 15;
    }
  });
  
  // Final Score
  audit.score = Math.max(0, audit.score);
  
  console.log('\n๐Ÿ“Š AUDIT SUMMARY');
  console.log('โ•'.repeat(50));
  console.log(`Security Score: ${audit.score}/100`);
  console.log(`Forms analyzed: ${audit.forms.length}`);
  console.log(`HTTPS only: ${audit.httpsOnly ? 'โœ…' : 'โŒ'}`);
  console.log(`CSRF protection: ${audit.csrfProtection ? 'โœ…' : 'โŒ'}`);
  console.log(`XSS protection: ${audit.xssProtection ? 'โœ…' : 'โŒ'}`);
  
  // Risk level
  let risk = 'LOW';
  if (audit.score < 50) risk = 'HIGH';
  else if (audit.score < 70) risk = 'MEDIUM';
  
  console.log(`Risk Level: ${risk}`);
  
  // Issues summary
  if (audit.fileUploadRisks.length > 0 || audit.dataLeakage.length > 0) {
    console.log('\nโŒ Critical Issues:');
    [...audit.fileUploadRisks, ...audit.dataLeakage].forEach(issue => {
      console.log(`  โ€ข ${issue}`);
    });
  }
  
  // Recommendations
  console.log('\n๐Ÿ’ก TOP RECOMMENDATIONS:');
  
  if (!audit.httpsOnly) {
    console.log('1. Use HTTPS for all forms');
  }
  if (!audit.csrfProtection) {
    console.log('2. Implement CSRF protection');
  }
  if (!audit.xssProtection) {
    console.log('3. Add Content Security Policy');
  }
  
  audit.recommendations.forEach((rec, i) => {
    console.log(`${i + 4}. ${rec}`);
  });
  
  console.log('\n๐Ÿ“š Additional Steps:');
  console.log('โ€ข Validate all input server-side');
  console.log('โ€ข Implement rate limiting');
  console.log('โ€ข Log and monitor form submissions');
  console.log('โ€ข Regular security testing');
  
  return audit;
}

// Run the complete audit
completeFormSecurityAudit();

The Bottom Line

Form security is your first line of defense:

  • Every form is an attack vector - Validate everything, trust nothing
  • CSRF attacks are still common - One token prevents account takeover
  • File uploads are extremely dangerous - One bad file pwns your server
  • XSS through forms affects everyone - Escaped input protects all users
  • Data leaks through autocomplete - Browsers remember everything

Secure every form. Validate every input. Protect every upload. Your users trust you with their data.


Analyze form security instantly: Fusebox detects form vulnerabilities, checks CSRF protection, validates file upload safety, and monitors data leakage while you browse. Secure your user inputs. $29 one-time purchase.