This document outlines the security measures, best practices, and considerations implemented in the LeetCode Documentation Generator Chrome extension. Security is a critical aspect of browser extensions due to their privileged access to web pages and user data.
- Security Architecture
- Permission Model
- Data Security
- Content Security Policy
- Input Validation
- Secure Coding Practices
- Vulnerability Assessment
- Security Testing
- Incident Response
-
User's LeetCode Submission Data
- Problem names and descriptions
- Source code solutions
- Submission URLs and metadata
-
User's Personal Information
- Student names
- Problem set titles
- Academic work documentation
-
Browser Security Context
- Extension permissions and capabilities
- Access to LeetCode domain
- Local storage data
-
Data Exfiltration
- Unauthorized transmission of user data
- Malicious code injection
- Third-party service compromise
-
Code Injection Attacks
- Cross-Site Scripting (XSS)
- Content Script injection
- Malicious payload execution
-
Permission Abuse
- Excessive permission usage
- Unauthorized domain access
- Storage manipulation
-
Supply Chain Attacks
- Compromised dependencies
- Malicious CDN resources
- Build process compromise
graph TB
subgraph "Trusted Zone"
A[Extension Core]
B[Local Storage]
C[User Interface]
end
subgraph "Semi-Trusted Zone"
D[LeetCode Pages]
E[Content Scripts]
end
subgraph "Untrusted Zone"
F[External CDNs]
G[Network Resources]
H[User Input]
end
A --> E
E --> D
A --> F
H --> A
style A fill:#90EE90
style B fill:#90EE90
style C fill:#90EE90
style D fill:#FFE4B5
style E fill:#FFE4B5
style F fill:#FFB6C1
style G fill:#FFB6C1
style H fill:#FFB6C1
The extension follows the principle of least privilege, requesting only essential permissions:
{
"permissions": [
"storage", // Required for data persistence
"activeTab" // Required for page interaction and refresh
],
"host_permissions": [
"https://leetcode.com/*" // Limited to LeetCode domain only
]
}- Purpose: Store problem sets and user preferences locally
- Scope: Chrome local storage only (no sync storage)
- Data: Problem metadata, code, and user-provided information
- Security: Data remains on user's device, no external transmission
- Purpose: Read LeetCode submission pages and refresh when needed
- Scope: Only active tab, only when user interacts with extension
- Data: DOM content from LeetCode submission pages
- Security: No persistent access, no background monitoring
- Purpose: Content script injection for data extraction
- Scope: Limited to
https://leetcode.com/*domain only - Data: Problem names, code, and submission metadata
- Security: HTTPS-only, specific domain restriction
// Verify permissions at runtime
async function validatePermissions() {
const requiredPermissions = ['storage', 'activeTab'];
const hasPermissions = await chrome.permissions.contains({
permissions: requiredPermissions,
origins: ['https://leetcode.com/*']
});
if (!hasPermissions) {
throw new Error('Required permissions not granted');
}
}- User's Source Code: Intellectual property, academic work
- Student Names: Personal identifying information
- Problem Set Titles: Academic context information
- Problem Names: Publicly available on LeetCode
- Submission URLs: Public LeetCode URLs
- Programming Languages: Public metadata
- Collect only necessary data for functionality
- No tracking or analytics data collection
- No user behavior monitoring
- All data stored locally on user's device
- No data transmission to external servers
- No cloud storage or backup services
- Data persists until user explicitly deletes it
- No automatic data expiration
- User has full control over data lifecycle
// Secure storage implementation
class SecureStorage {
static async saveData(key, data) {
// Validate data before storage
const validatedData = this.validateData(data);
// Sanitize data to prevent injection
const sanitizedData = this.sanitizeData(validatedData);
// Store with error handling
try {
await chrome.storage.local.set({ [key]: sanitizedData });
} catch (error) {
console.error('Storage operation failed:', error);
throw new Error('Failed to save data securely');
}
}
static validateData(data) {
// Implement comprehensive validation
if (!data || typeof data !== 'object') {
throw new Error('Invalid data format');
}
return data;
}
static sanitizeData(data) {
// Remove potentially dangerous content
// Escape HTML entities
// Validate data types
return data;
}
}The extension implements a strict Content Security Policy to prevent code injection:
{
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com;"
}
}- Purpose: Only allow scripts from extension package
- Security: Prevents external script injection
- Exception: CDN scripts loaded via separate mechanism
- Purpose: Restrict object/embed sources
- Security: Prevents malicious plugin loading
- Purpose: Allow extension styles and Font Awesome
- Security: Limited to trusted CDN for icons
- Note:
unsafe-inlinerequired for dynamic styling
// Validate CSP compliance
function validateCSP() {
// Check for inline scripts (should be none)
const inlineScripts = document.querySelectorAll('script:not([src])');
if (inlineScripts.length > 0) {
console.warn('Inline scripts detected - CSP violation');
}
// Check for eval usage (should be none)
const originalEval = window.eval;
window.eval = function() {
console.error('eval() usage detected - security violation');
throw new Error('eval() is not allowed');
};
}All user inputs are validated at multiple layers:
- Client-Side Validation: Immediate feedback and basic checks
- Business Logic Validation: Comprehensive validation before processing
- Storage Validation: Final validation before persistence
class InputValidator {
static validateProblemSetInfo(info) {
const errors = [];
// Title validation
if (!info.title || typeof info.title !== 'string') {
errors.push('Title is required and must be a string');
} else if (info.title.length < 2 || info.title.length > 200) {
errors.push('Title must be between 2 and 200 characters');
} else if (this.containsMaliciousContent(info.title)) {
errors.push('Title contains invalid characters');
}
// Student name validation
if (!info.submittedBy || typeof info.submittedBy !== 'string') {
errors.push('Student name is required and must be a string');
} else if (info.submittedBy.length < 2 || info.submittedBy.length > 100) {
errors.push('Student name must be between 2 and 100 characters');
} else if (this.containsMaliciousContent(info.submittedBy)) {
errors.push('Student name contains invalid characters');
}
return {
valid: errors.length === 0,
errors: errors
};
}
static validateProblemData(problem) {
const errors = [];
// Problem name validation
if (!problem.name || typeof problem.name !== 'string') {
errors.push('Problem name is required');
} else if (problem.name.length > 300) {
errors.push('Problem name too long');
} else if (this.containsMaliciousContent(problem.name)) {
errors.push('Problem name contains invalid characters');
}
// Code validation
if (!problem.code || typeof problem.code !== 'string') {
errors.push('Code is required');
} else if (problem.code.length > 100000) {
errors.push('Code exceeds maximum length');
}
// URL validation
if (!problem.submissionLink || !this.isValidLeetCodeUrl(problem.submissionLink)) {
errors.push('Invalid LeetCode submission URL');
}
return {
valid: errors.length === 0,
errors: errors
};
}
static containsMaliciousContent(input) {
// Check for potential XSS patterns
const maliciousPatterns = [
/<script/i,
/javascript:/i,
/on\w+\s*=/i,
/<iframe/i,
/<object/i,
/<embed/i
];
return maliciousPatterns.some(pattern => pattern.test(input));
}
static isValidLeetCodeUrl(url) {
try {
const urlObj = new URL(url);
return urlObj.hostname === 'leetcode.com' &&
urlObj.protocol === 'https:' &&
(urlObj.pathname.includes('/submissions/') ||
urlObj.pathname.includes('/problems/'));
} catch {
return false;
}
}
static sanitizeHtml(input) {
// Create a temporary element to leverage browser's HTML parsing
const temp = document.createElement('div');
temp.textContent = input;
return temp.innerHTML;
}
}// Safe DOM manipulation
function safeSetTextContent(element, text) {
// Always use textContent, never innerHTML for user data
element.textContent = text;
}
function safeCreateElement(tag, text, className) {
const element = document.createElement(tag);
if (text) {
element.textContent = text; // Safe text insertion
}
if (className) {
element.className = className; // Safe class assignment
}
return element;
}
// Escape HTML entities
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}// ❌ Dangerous - Never use eval()
eval(userInput);
// ❌ Dangerous - Never use Function constructor
new Function(userInput)();
// ✅ Safe - Use proper parsing
JSON.parse(userInput);// ❌ Dangerous - innerHTML with user data
element.innerHTML = userInput;
// ✅ Safe - textContent for user data
element.textContent = userInput;
// ✅ Safe - createElement for structure
const div = document.createElement('div');
div.textContent = userInput;// ✅ Safe - Proper event listener attachment
button.addEventListener('click', handleClick);
// ❌ Dangerous - Inline event handlers with user data
button.onclick = new Function(userInput);// ✅ Safe - URL validation
function isValidUrl(url) {
try {
const urlObj = new URL(url);
return urlObj.protocol === 'https:' &&
urlObj.hostname === 'leetcode.com';
} catch {
return false;
}
}// Secure error handling - don't expose sensitive information
function handleError(error, context) {
// Log detailed error for debugging (not visible to user)
console.error(`Error in ${context}:`, error);
// Show generic error to user
const userMessage = 'An error occurred. Please try again.';
showUserMessage(userMessage, 'error');
// Don't expose stack traces or internal details
return {
success: false,
message: userMessage
};
}- Risk: Malicious script injection through user input
- Mitigation: Input validation, output encoding, CSP
- Testing: Inject XSS payloads in all input fields
- Risk: Malicious content scripts on compromised pages
- Mitigation: Strict CSP, input validation, secure messaging
- Testing: Test on pages with malicious scripts
- Risk: Abuse of granted permissions
- Mitigation: Minimal permissions, runtime validation
- Testing: Verify permission usage is justified
- Risk: Unauthorized data transmission
- Mitigation: No external network requests, local storage only
- Testing: Monitor network traffic during operation
- No use of
eval()orFunction()constructor - No
innerHTMLwith user data - All user inputs are validated and sanitized
- No hardcoded secrets or credentials
- Proper error handling without information disclosure
- CSP compliance verified
- Minimal permission usage
- No external data transmission
- Extension loads without CSP violations
- All network requests are to approved domains
- User data is properly sanitized before display
- No JavaScript errors that could indicate injection
- Storage operations are secure and validated
// Security test suite
describe('Security Tests', () => {
describe('Input Validation', () => {
it('should reject XSS payloads', () => {
const xssPayloads = [
'<script>alert("xss")</script>',
'javascript:alert("xss")',
'<img src=x onerror=alert("xss")>',
'<iframe src="javascript:alert(\'xss\')"></iframe>'
];
xssPayloads.forEach(payload => {
expect(() => validateInput(payload)).toThrow();
});
});
it('should sanitize HTML content', () => {
const maliciousHtml = '<script>alert("xss")</script>Hello';
const sanitized = sanitizeHtml(maliciousHtml);
expect(sanitized).not.toContain('<script>');
expect(sanitized).toContain('Hello');
});
});
describe('URL Validation', () => {
it('should only allow LeetCode URLs', () => {
const validUrl = 'https://leetcode.com/problems/two-sum/submissions/123/';
const invalidUrl = 'https://malicious.com/fake-leetcode';
expect(isValidLeetCodeUrl(validUrl)).toBe(true);
expect(isValidLeetCodeUrl(invalidUrl)).toBe(false);
});
});
});- Input Fuzzing: Test with malformed, oversized, and malicious inputs
- XSS Testing: Inject XSS payloads in all input fields
- URL Manipulation: Test with malicious URLs and redirects
- Storage Testing: Verify data integrity and access controls
- Permission Testing: Verify minimal permission usage
- Network Testing: Monitor for unauthorized network requests
// Test case examples
const securityTestCases = {
xssPayloads: [
'<script>alert("xss")</script>',
'javascript:alert("xss")',
'<img src=x onerror=alert("xss")>',
'<svg onload=alert("xss")>',
'<iframe src="javascript:alert(\'xss\')"></iframe>',
'"><script>alert("xss")</script>',
'\';alert("xss");//'
],
maliciousUrls: [
'javascript:alert("xss")',
'data:text/html,<script>alert("xss")</script>',
'https://malicious.com/fake-leetcode',
'http://leetcode.com/', // HTTP instead of HTTPS
'https://leetcode.evil.com/',
'https://evil.com/leetcode.com/'
],
oversizedInputs: {
title: 'A'.repeat(1000),
code: 'A'.repeat(200000),
name: 'B'.repeat(500)
}
};- Critical: Data breach, code execution, permission escalation
- High: XSS vulnerability, unauthorized access
- Medium: Input validation bypass, information disclosure
- Low: Minor security configuration issues
- Monitor for security-related errors or anomalies
- Analyze reported security issues
- Assess impact and severity
- Disable affected functionality if necessary
- Prevent further exploitation
- Preserve evidence for analysis
- Fix underlying vulnerability
- Test fix thoroughly
- Deploy updated version
- Document lessons learned
- Update security measures
- Improve detection capabilities
For security-related issues:
- Email: Create security@leetcode-doc-generator.com
- GitHub: Use private security advisory
- Response Time: 24-48 hours for critical issues
We encourage responsible disclosure of security vulnerabilities:
- Report privately through appropriate channels
- Allow reasonable time for fix development
- Coordinate disclosure timing with maintainers
- Provide clear details about the vulnerability
- Review and update dependencies
- Check for new security advisories
- Review access logs and error reports
- Conduct security code review
- Update threat model
- Review and test incident response procedures
- Comprehensive security audit
- Penetration testing
- Security training for contributors
// Security monitoring implementation
class SecurityMonitor {
static logSecurityEvent(event, severity, details) {
const logEntry = {
timestamp: new Date().toISOString(),
event: event,
severity: severity,
details: details,
userAgent: navigator.userAgent,
url: window.location.href
};
console.warn('Security Event:', logEntry);
// In production, send to security monitoring service
// this.sendToSecurityService(logEntry);
}
static detectAnomalousActivity() {
// Monitor for unusual patterns
// - Rapid successive operations
// - Large data operations
// - Unusual error patterns
}
}This security documentation provides a comprehensive framework for maintaining the security posture of the LeetCode Documentation Generator extension throughout its lifecycle.