409e92d6ae
Build and Push Docker Images / Build Docker Image (push) Has been cancelled
Build and Push Docker Images / Build Railway Docker Image (push) Has been cancelled
Build and Publish n8n Docker Image / test-image (push) Has been cancelled
Dependency Compatibility Check / Fresh Install Dependency Check (push) Has been cancelled
Build and Publish n8n Docker Image / build-and-push (push) Has been cancelled
Build and Publish n8n Docker Image / create-release (push) Has been cancelled
Automated Release / Detect Version Change (push) Has been cancelled
Automated Release / Generate Release Notes (push) Has been cancelled
Automated Release / Create GitHub Release (push) Has been cancelled
Automated Release / Package MCPB Bundle (push) Has been cancelled
Automated Release / Build and Verify (push) Has been cancelled
Automated Release / Publish to NPM (push) Has been cancelled
Automated Release / Build and Push Docker Images (push) Has been cancelled
Automated Release / Update Documentation (push) Has been cancelled
Automated Release / Notify Release Completion (push) Has been cancelled
Secret Scan / secretlint (push) Has been cancelled
Test Suite / test (push) Has been cancelled
Test Suite / cjs-runtime (push) Has been cancelled
Test Suite / publish-results (push) Has been cancelled
105 lines
3.0 KiB
JavaScript
105 lines
3.0 KiB
JavaScript
#!/usr/bin/env node
|
|
import axios from 'axios';
|
|
import { spawn } from 'child_process';
|
|
|
|
async function testMaliciousHeaders() {
|
|
console.log('🔒 Testing Security Fixes...\n');
|
|
|
|
// Start server with TRUST_PROXY enabled
|
|
const serverProcess = spawn('node', ['dist/mcp/index.js'], {
|
|
env: {
|
|
...process.env,
|
|
MCP_MODE: 'http',
|
|
AUTH_TOKEN: 'test-security-token-32-characters-long',
|
|
PORT: '3999',
|
|
TRUST_PROXY: '1'
|
|
}
|
|
});
|
|
|
|
// Wait for server to start
|
|
await new Promise(resolve => {
|
|
serverProcess.stdout.on('data', (data) => {
|
|
if (data.toString().includes('Press Ctrl+C to stop')) {
|
|
resolve(undefined);
|
|
}
|
|
});
|
|
});
|
|
|
|
const testCases = [
|
|
{
|
|
name: 'Valid proxy headers',
|
|
headers: {
|
|
'X-Forwarded-Host': 'example.com',
|
|
'X-Forwarded-Proto': 'https'
|
|
}
|
|
},
|
|
{
|
|
name: 'Malicious host header (with path)',
|
|
headers: {
|
|
'X-Forwarded-Host': 'evil.com/path/to/evil',
|
|
'X-Forwarded-Proto': 'https'
|
|
}
|
|
},
|
|
{
|
|
name: 'Malicious host header (with @)',
|
|
headers: {
|
|
'X-Forwarded-Host': 'user@evil.com',
|
|
'X-Forwarded-Proto': 'https'
|
|
}
|
|
},
|
|
{
|
|
name: 'Invalid hostname (multiple dots)',
|
|
headers: {
|
|
'X-Forwarded-Host': '.....',
|
|
'X-Forwarded-Proto': 'https'
|
|
}
|
|
},
|
|
{
|
|
name: 'IPv6 address',
|
|
headers: {
|
|
'X-Forwarded-Host': '[::1]:3000',
|
|
'X-Forwarded-Proto': 'https'
|
|
}
|
|
}
|
|
];
|
|
|
|
for (const testCase of testCases) {
|
|
try {
|
|
const response = await axios.get('http://localhost:3999/', {
|
|
headers: testCase.headers,
|
|
timeout: 2000
|
|
});
|
|
|
|
const endpoints = response.data.endpoints;
|
|
const healthUrl = endpoints?.health?.url || 'N/A';
|
|
|
|
console.log(`✅ ${testCase.name}`);
|
|
console.log(` Response: ${healthUrl}`);
|
|
|
|
// Check if malicious headers were blocked.
|
|
//
|
|
// NOTE: this is a substring presence check, not URL sanitization.
|
|
// The goal is to detect whether ANY of the attacker-supplied markers
|
|
// leaked into the server's echoed health URL — a hostname-only check
|
|
// would miss path/userinfo injection, which is exactly what we're
|
|
// testing for. CodeQL js/incomplete-url-substring-sanitization
|
|
// flagged this as if it were an auth gate; it is not.
|
|
if (testCase.name.includes('Malicious') || testCase.name.includes('Invalid')) {
|
|
const maliciousMarkers = ['evil.com', '@', '.....'];
|
|
const leaked = maliciousMarkers.some(marker => healthUrl.indexOf(marker) !== -1);
|
|
if (leaked) {
|
|
console.log(' ❌ SECURITY ISSUE: Malicious header was not blocked!');
|
|
} else {
|
|
console.log(' ✅ Malicious header was blocked');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.log(`❌ ${testCase.name} - Request failed`);
|
|
}
|
|
console.log('');
|
|
}
|
|
|
|
serverProcess.kill();
|
|
}
|
|
|
|
testMaliciousHeaders().catch(console.error); |