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.