mcp-sanitizer
Version:
Comprehensive security sanitization library for Model Context Protocol (MCP) servers with trusted security libraries
641 lines (556 loc) • 18.5 kB
JavaScript
/**
* Security Policies for MCP Sanitizer
*
* This module provides predefined security policies that can be used to configure
* the MCP Sanitizer for different security requirements. Similar to DOMPurify's
* approach, this provides easy-to-use presets for common security scenarios.
*
* Security Policies Available:
* - STRICT: Maximum security, blocks most potentially dangerous content
* - MODERATE: Balanced security and functionality
* - PERMISSIVE: Minimal restrictions, allows most content with basic validation
* - DEVELOPMENT: Relaxed settings for development environments
* - PRODUCTION: Secure settings optimized for production use
*/
// const { DEFAULT_CONFIG } = require('./default-config') // Unused - commented out to fix ESLint
/**
* STRICT Security Policy
* Maximum security with aggressive filtering and minimal allowed content.
* Recommended for high-security environments and untrusted input processing.
*/
const STRICT_POLICY = {
// Network restrictions
allowedProtocols: ['https'], // Only secure HTTPS allowed
// Aggressive length and depth limits
maxStringLength: 1000, // Very short strings only
maxDepth: 3, // Shallow object nesting
maxArrayLength: 100, // Small arrays only
maxObjectKeys: 20, // Limited object complexity
// Minimal file type support
allowedFileExtensions: ['.txt', '.json'],
// Comprehensive pattern blocking
blockedPatterns: [
// All template injection patterns
/\$\{.*?\}|\{\{.*?\}\}|<%.*?%>|\[\[.*?\]\]/,
// All prototype pollution patterns
/__proto__|constructor\.prototype|prototype\.constructor|prototype\[|constructor\[/i,
// All code execution patterns
/require\s*\(|import\s*\(|eval\s*\(|Function\s*\(|setTimeout\s*\(|setInterval\s*\(/i,
// All script patterns
/<!--[\s\S]*?-->|<script[\s\S]*?<\/script>|<[^>]*on\w+\s*=|javascript:|data:/i,
// All command patterns
/\|\s*\w+|&&|\|\||;|`|\$\(|\$\{/,
// Path traversal
/\.\.\//,
// Any SQL-like syntax
/--[\s\S]*$|\/\*[\s\S]*?\*\/|'[^']*'|"[^"]*"/,
// File system access patterns
/file:\/\/|ftp:\/\/|\\\\/,
// Network access patterns
/http:\/\/localhost|http:\/\/127\.|http:\/\/10\.|http:\/\/192\.168\./i
],
// Extensive SQL keyword blocking
sqlKeywords: [
'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER', 'TRUNCATE',
'UNION', 'EXEC', 'EXECUTE', 'DECLARE', 'CAST', 'CONVERT', 'SUBSTRING',
'ASCII', 'CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR', 'CONCAT', 'REPLACE',
'xp_', 'sp_', 'sys', 'INFORMATION_SCHEMA', 'SYSOBJECTS', 'SYSCOLUMNS',
'OR 1=1', 'OR 1 = 1', 'AND 1=1', 'AND 1 = 1', '--', '/*', '*/',
'WAITFOR', 'DELAY', 'BENCHMARK', 'SLEEP', 'PG_SLEEP'
],
// Strict command blocking
blockedCommands: [
'rm', 'del', 'delete', 'format', 'mkfs', 'dd', 'mv', 'cp', 'chmod', 'chown',
'nc', 'netcat', 'curl', 'wget', 'ping', 'nslookup', 'dig', 'telnet', 'ssh',
'ps', 'top', 'whoami', 'id', 'uname', 'hostname', 'ifconfig', 'ipconfig',
'kill', 'killall', 'pkill', 'sudo', 'su', 'passwd', 'useradd', 'userdel',
'tar', 'zip', 'unzip', 'gzip', 'gunzip', 'cat', 'head', 'tail', 'less', 'more'
],
// Security settings
strictMode: true,
logSecurityEvents: true,
blockOnSeverity: 'medium', // Block even medium severity issues
// Pattern detection - all enabled
patternDetection: {
enableCommandInjection: true,
enableSQLInjection: true,
enablePrototypePollution: true,
enableTemplateInjection: true,
enableXSSDetection: true,
enablePathTraversal: true
},
// Restrictive context settings
contextSettings: {
filePath: {
allowAbsolutePaths: false,
allowedDirectories: [],
blockedDirectories: ['*'] // Block all directories
},
url: {
allowPrivateIPs: false,
allowLocalhostWithoutPort: false,
maxURLLength: 512,
blockedDomains: ['localhost', '127.0.0.1', '0.0.0.0'],
allowedDomains: [] // Must explicitly allow domains
},
command: {
allowedCommands: [], // No commands allowed
maxCommandLength: 0
}
},
// Conservative performance settings
performance: {
timeoutMs: 1000,
maxConcurrentRequests: 10,
enableCaching: false
}
};
/**
* MODERATE Security Policy
* Balanced approach between security and functionality.
* Suitable for most production applications with moderate security requirements.
*/
const MODERATE_POLICY = {
// Standard protocols
allowedProtocols: ['http', 'https', 'mcp'],
// Reasonable limits
maxStringLength: 5000,
maxDepth: 8,
maxArrayLength: 500,
maxObjectKeys: 50,
// Common file types
allowedFileExtensions: ['.txt', '.json', '.md', '.csv', '.yaml', '.yml'],
// Core security patterns
blockedPatterns: [
/\$\{.*?\}|\{\{.*?\}\}|<%.*?%>/,
/__proto__|constructor\.prototype|prototype\.constructor/i,
/require\s*\(|import\s*\(|eval\s*\(|Function\s*\(/i,
/<!--[\s\S]*?-->|<script[\s\S]*?<\/script>|<[^>]*on\w+\s*=|javascript:/i,
/\|\s*\w+|&&|\|\||;|`/,
/\.\.\//
],
// Essential SQL keywords
sqlKeywords: [
'DROP', 'DELETE', 'INSERT', 'UPDATE', 'CREATE', 'ALTER', 'TRUNCATE',
'UNION', 'EXEC', 'EXECUTE', 'xp_', 'sp_', 'INFORMATION_SCHEMA',
'OR 1=1', 'OR 1 = 1', 'AND 1=1', 'AND 1 = 1', '--', '/*', '*/'
],
// Common dangerous commands
blockedCommands: [
'rm', 'del', 'delete', 'format', 'mkfs', 'dd',
'nc', 'netcat', 'curl', 'wget',
'kill', 'killall', 'pkill', 'sudo', 'su'
],
// Balanced security settings
strictMode: false,
logSecurityEvents: true,
blockOnSeverity: 'high',
// Most detection enabled
patternDetection: {
enableCommandInjection: true,
enableSQLInjection: true,
enablePrototypePollution: true,
enableTemplateInjection: true,
enableXSSDetection: true,
enablePathTraversal: true
},
// Moderate context restrictions
contextSettings: {
filePath: {
allowAbsolutePaths: false,
allowedDirectories: ['./data', './uploads', './temp'],
blockedDirectories: [
'/etc', '/proc', '/sys', '/dev', '/root',
'C:\\Windows', 'C:\\System32', 'C:\\Program Files'
]
},
url: {
allowPrivateIPs: false,
allowLocalhostWithoutPort: false,
maxURLLength: 2048,
blockedDomains: [],
allowedDomains: []
},
command: {
allowedCommands: ['ls', 'dir', 'pwd', 'whoami'],
maxCommandLength: 500
}
},
// Standard performance settings
performance: {
timeoutMs: 3000,
maxConcurrentRequests: 50,
enableCaching: false
}
};
/**
* PERMISSIVE Security Policy
* Minimal restrictions with basic validation only.
* Suitable for trusted environments and development scenarios.
*/
const PERMISSIVE_POLICY = {
// All common protocols
allowedProtocols: ['http', 'https', 'ftp', 'mcp', 'file'],
// Generous limits
maxStringLength: 50000,
maxDepth: 20,
maxArrayLength: 5000,
maxObjectKeys: 500,
// Many file types allowed
allowedFileExtensions: [
'.txt', '.json', '.md', '.csv', '.xml', '.yaml', '.yml',
'.js', '.ts', '.html', '.css', '.log', '.conf', '.ini'
],
// Minimal pattern blocking - only the most dangerous
blockedPatterns: [
/eval\s*\(/i, // Direct eval calls
/<script[\s\S]*?<\/script>/i, // Script tags
/__proto__\s*:/ // Direct prototype pollution
],
// Minimal SQL keyword blocking
sqlKeywords: [
'DROP DATABASE', 'DROP TABLE', 'DELETE FROM', 'TRUNCATE TABLE',
'xp_cmdshell', 'sp_configure', '--', '/*'
],
// Few blocked commands
blockedCommands: [
'rm -rf', 'del /s', 'format', 'mkfs',
'sudo rm', 'sudo del'
],
// Relaxed security settings
strictMode: false,
logSecurityEvents: false,
blockOnSeverity: 'critical',
// Selective detection
patternDetection: {
enableCommandInjection: true,
enableSQLInjection: true,
enablePrototypePollution: true,
enableTemplateInjection: false, // Disabled for flexibility
enableXSSDetection: true,
enablePathTraversal: false // Disabled for flexibility
},
// Permissive context settings
contextSettings: {
filePath: {
allowAbsolutePaths: true,
allowedDirectories: ['*'],
blockedDirectories: ['/etc/passwd', '/etc/shadow']
},
url: {
allowPrivateIPs: true,
allowLocalhostWithoutPort: true,
maxURLLength: 8192,
blockedDomains: [],
allowedDomains: []
},
command: {
allowedCommands: ['*'],
maxCommandLength: 2000
}
},
// High performance settings
performance: {
timeoutMs: 10000,
maxConcurrentRequests: 200,
enableCaching: true
}
};
/**
* DEVELOPMENT Security Policy
* Optimized for development environments with debugging capabilities.
* Includes relaxed restrictions but maintains core security.
*/
const DEVELOPMENT_POLICY = {
...MODERATE_POLICY,
// Development-friendly protocols
allowedProtocols: ['http', 'https', 'mcp', 'file'],
// Higher limits for development data
maxStringLength: 20000,
maxDepth: 15,
maxArrayLength: 2000,
maxObjectKeys: 200,
// Development file types
allowedFileExtensions: [
'.txt', '.json', '.md', '.csv', '.xml', '.yaml', '.yml',
'.js', '.ts', '.html', '.css', '.log', '.conf', '.ini',
'.env', '.example', '.template'
],
// Less strict patterns for development flexibility
blockedPatterns: [
/__proto__|constructor\.prototype/i,
/eval\s*\(/i,
/<script[\s\S]*?<\/script>/i,
/\|\s*rm|\|\s*del/
],
// Development settings
strictMode: false,
logSecurityEvents: true,
blockOnSeverity: 'high',
// Allow localhost access
contextSettings: {
...MODERATE_POLICY.contextSettings,
url: {
allowPrivateIPs: true,
allowLocalhostWithoutPort: true,
maxURLLength: 4096,
blockedDomains: [],
allowedDomains: []
},
command: {
allowedCommands: ['ls', 'dir', 'pwd', 'whoami', 'echo', 'cat', 'head', 'tail'],
maxCommandLength: 1000
}
},
// Relaxed performance for debugging
performance: {
timeoutMs: 15000,
maxConcurrentRequests: 100,
enableCaching: false // Disabled for fresh results during development
}
};
/**
* PRODUCTION Security Policy
* Optimized for production environments with security and performance balance.
* Stricter than moderate but maintains necessary functionality.
*/
const PRODUCTION_POLICY = {
...MODERATE_POLICY,
// Production-secure protocols only
allowedProtocols: ['https', 'mcp'],
// Production-appropriate limits
maxStringLength: 8000,
maxDepth: 10,
maxArrayLength: 1000,
maxObjectKeys: 100,
// Production file types
allowedFileExtensions: ['.txt', '.json', '.md', '.csv', '.yaml', '.yml', '.log'],
// Enhanced security patterns
blockedPatterns: [
...MODERATE_POLICY.blockedPatterns,
/file:\/\/|ftp:\/\//i, // Block file and FTP protocols
/data:\/\/[^,]*base64/i, // Block base64 data URLs
/\beval\b|\bexec\b/i // Block eval and exec keywords
],
// Production security settings
strictMode: true,
logSecurityEvents: true,
blockOnSeverity: 'medium',
// All detection enabled for production
patternDetection: {
enableCommandInjection: true,
enableSQLInjection: true,
enablePrototypePollution: true,
enableTemplateInjection: true,
enableXSSDetection: true,
enablePathTraversal: true
},
// Secure context settings
contextSettings: {
filePath: {
allowAbsolutePaths: false,
allowedDirectories: ['./data', './uploads'],
blockedDirectories: [
'/etc', '/proc', '/sys', '/dev', '/root', '/var/log',
'C:\\Windows', 'C:\\System32', 'C:\\Program Files'
]
},
url: {
allowPrivateIPs: false,
allowLocalhostWithoutPort: false,
maxURLLength: 2048,
blockedDomains: ['localhost', '127.0.0.1', '0.0.0.0'],
allowedDomains: [] // Should be configured per application
},
command: {
allowedCommands: [], // No commands in production by default
maxCommandLength: 0
}
},
// Production performance settings
performance: {
timeoutMs: 5000,
maxConcurrentRequests: 100,
enableCaching: true // Enable for production performance
}
};
/**
* Available security policies
*/
const SECURITY_POLICIES = {
STRICT: STRICT_POLICY,
MODERATE: MODERATE_POLICY,
PERMISSIVE: PERMISSIVE_POLICY,
DEVELOPMENT: DEVELOPMENT_POLICY,
PRODUCTION: PRODUCTION_POLICY
};
/**
* Policy names for validation
*/
const POLICY_NAMES = Object.keys(SECURITY_POLICIES);
/**
* Get a security policy by name
* @param {string} policyName - Name of the security policy
* @returns {Object} Security policy configuration
* @throws {Error} If policy name is invalid
*/
function getSecurityPolicy (policyName) {
if (typeof policyName !== 'string') {
throw new Error('Policy name must be a string');
}
const upperPolicyName = policyName.toUpperCase();
if (!SECURITY_POLICIES[upperPolicyName]) {
throw new Error(`Invalid security policy: ${policyName}. Available policies: ${POLICY_NAMES.join(', ')}`);
}
// Deep clone function that preserves RegExp objects
function deepClone (obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
const cloned = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
return deepClone(SECURITY_POLICIES[upperPolicyName]);
}
/**
* Create a custom policy by extending an existing policy
* @param {string} basePolicyName - Base policy to extend
* @param {Object} customizations - Custom settings to override
* @returns {Object} Custom security policy
*/
function createCustomPolicy (basePolicyName, customizations = {}) {
const basePolicy = getSecurityPolicy(basePolicyName);
// Deep merge function that handles RegExp objects
function deepMerge (target, source) {
const result = { ...target };
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (typeof source[key] === 'object' &&
source[key] !== null &&
!Array.isArray(source[key]) &&
!(source[key] instanceof RegExp)) {
// Deep merge objects
result[key] = deepMerge(target[key] || {}, source[key]);
} else if (source[key] instanceof RegExp) {
// Clone RegExp objects
result[key] = new RegExp(source[key].source, source[key].flags);
} else if (Array.isArray(source[key])) {
// For arrays, completely replace with source array (cloning RegExp objects)
result[key] = source[key].map(item =>
item instanceof RegExp
? new RegExp(item.source, item.flags)
: item
);
} else {
// For primitive values, use source value
result[key] = source[key];
}
}
}
return result;
}
return deepMerge(basePolicy, customizations);
}
/**
* Get policy recommendations based on environment
* @param {string} environment - Environment type ('development', 'staging', 'production')
* @param {string} trustLevel - Trust level ('high', 'medium', 'low')
* @returns {Object} Policy recommendation
*/
function getPolicyRecommendation (environment = 'production', trustLevel = 'low') {
const recommendations = {
development: {
high: 'PERMISSIVE',
medium: 'DEVELOPMENT',
low: 'MODERATE'
},
staging: {
high: 'MODERATE',
medium: 'MODERATE',
low: 'PRODUCTION'
},
production: {
high: 'MODERATE',
medium: 'PRODUCTION',
low: 'STRICT'
}
};
const envRecommendations = recommendations[environment.toLowerCase()];
if (!envRecommendations) {
throw new Error(`Invalid environment: ${environment}. Use 'development', 'staging', or 'production'`);
}
const policyName = envRecommendations[trustLevel.toLowerCase()];
if (!policyName) {
throw new Error(`Invalid trust level: ${trustLevel}. Use 'high', 'medium', or 'low'`);
}
return {
recommended: policyName,
policy: getSecurityPolicy(policyName),
rationale: `Recommended ${policyName} policy for ${environment} environment with ${trustLevel} trust level`
};
}
/**
* Validate that a policy meets minimum security requirements
* @param {Object} policy - Policy to validate
* @param {Object} requirements - Minimum security requirements
* @returns {Object} Validation result
*/
function validatePolicyRequirements (policy, requirements = {}) {
const result = {
valid: true,
violations: [],
warnings: []
};
// Check basic security requirements
if (requirements.requireHTTPS && policy.allowedProtocols.includes('http')) {
result.violations.push('Policy allows HTTP protocol when HTTPS is required');
result.valid = false;
}
if (requirements.maxStringLength && policy.maxStringLength > requirements.maxStringLength) {
result.violations.push(`Policy allows strings longer than required maximum: ${requirements.maxStringLength}`);
result.valid = false;
}
if (requirements.blockSeverity) {
const severityOrder = ['low', 'medium', 'high', 'critical'];
const requiredIndex = severityOrder.indexOf(requirements.blockSeverity);
const policyIndex = severityOrder.indexOf(policy.blockOnSeverity);
if (policyIndex > requiredIndex) {
result.violations.push(`Policy blocks at ${policy.blockOnSeverity} severity when ${requirements.blockSeverity} or higher is required`);
result.valid = false;
}
}
// Check for security features
if (requirements.requireAllPatternDetection) {
const requiredDetections = Object.keys(policy.patternDetection);
for (const detection of requiredDetections) {
if (!policy.patternDetection[detection]) {
result.warnings.push(`Pattern detection disabled for ${detection}`);
}
}
}
return result;
}
module.exports = {
SECURITY_POLICIES,
POLICY_NAMES,
STRICT_POLICY,
MODERATE_POLICY,
PERMISSIVE_POLICY,
DEVELOPMENT_POLICY,
PRODUCTION_POLICY,
getSecurityPolicy,
createCustomPolicy,
getPolicyRecommendation,
validatePolicyRequirements
};