Enhance security by implementing command and argument validation in SupergatewayMCP. Added checks for banned commands, dangerous patterns, and potential shell injection attempts. Security validation is conditionally enabled based on the CUSTOM_MCP_SECURITY_CHECK environment variable.
This commit is contained in:
parent
8e7a3a8b37
commit
ca3818913e
|
|
@ -3,6 +3,136 @@ import { ICommonObject, INode, INodeData, INodeOptionsValue, INodeParams } from
|
|||
import { getNodeModulesPackagePath } from '../../../../src/utils'
|
||||
import { MCPToolkit } from '../core'
|
||||
|
||||
// List of dangerous commands that are banned for security reasons
|
||||
const BANNED_COMMANDS = [
|
||||
'sh',
|
||||
'bash',
|
||||
'zsh',
|
||||
'fish',
|
||||
'csh',
|
||||
'tcsh',
|
||||
'ksh',
|
||||
'dash',
|
||||
'/bin/sh',
|
||||
'/bin/bash',
|
||||
'/bin/zsh',
|
||||
'/bin/fish',
|
||||
'/bin/csh',
|
||||
'/bin/tcsh',
|
||||
'/bin/ksh',
|
||||
'/bin/dash',
|
||||
'/usr/bin/sh',
|
||||
'/usr/bin/bash',
|
||||
'/usr/bin/zsh',
|
||||
'/usr/bin/fish',
|
||||
'/usr/bin/csh',
|
||||
'/usr/bin/tcsh',
|
||||
'/usr/bin/ksh',
|
||||
'/usr/bin/dash',
|
||||
'cmd',
|
||||
'cmd.exe',
|
||||
'powershell',
|
||||
'powershell.exe',
|
||||
'pwsh',
|
||||
'pwsh.exe',
|
||||
'perl',
|
||||
'ruby',
|
||||
'php',
|
||||
'eval',
|
||||
'exec',
|
||||
'system'
|
||||
]
|
||||
|
||||
// Additional dangerous command patterns to check
|
||||
const DANGEROUS_PATTERNS = [
|
||||
/^\/bin\//,
|
||||
/^\/usr\/bin\//,
|
||||
/^\/usr\/local\/bin\//,
|
||||
/^\/sbin\//,
|
||||
/^\/usr\/sbin\//,
|
||||
/\.exe$/i,
|
||||
/\.bat$/i,
|
||||
/\.cmd$/i,
|
||||
/\.ps1$/i,
|
||||
/\.sh$/i
|
||||
]
|
||||
|
||||
function validateCommand(command: string): void {
|
||||
if (!command || typeof command !== 'string') {
|
||||
return
|
||||
}
|
||||
|
||||
const normalizedCommand = command.toLowerCase().trim()
|
||||
|
||||
// Check against banned commands list
|
||||
for (const bannedCmd of BANNED_COMMANDS) {
|
||||
if (
|
||||
normalizedCommand === bannedCmd.toLowerCase() ||
|
||||
normalizedCommand.endsWith(`/${bannedCmd.toLowerCase()}`) ||
|
||||
normalizedCommand.endsWith(`\\${bannedCmd.toLowerCase()}`)
|
||||
) {
|
||||
throw new Error(
|
||||
`Security Error: Command "${command}" is banned for security reasons. Shell access and executable commands are not allowed.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Check against dangerous patterns
|
||||
for (const pattern of DANGEROUS_PATTERNS) {
|
||||
if (pattern.test(normalizedCommand)) {
|
||||
throw new Error(`Security Error: Command "${command}" matches a dangerous pattern and is not allowed for security reasons.`)
|
||||
}
|
||||
}
|
||||
|
||||
// Additional checks for potential shell injection attempts
|
||||
if (
|
||||
normalizedCommand.includes('&&') ||
|
||||
normalizedCommand.includes('||') ||
|
||||
normalizedCommand.includes(';') ||
|
||||
normalizedCommand.includes('|') ||
|
||||
normalizedCommand.includes('`') ||
|
||||
normalizedCommand.includes('$(') ||
|
||||
normalizedCommand.includes('${')
|
||||
) {
|
||||
throw new Error(`Security Error: Command "${command}" contains potentially dangerous shell operators and is not allowed.`)
|
||||
}
|
||||
}
|
||||
|
||||
function validateArguments(args: string[]): void {
|
||||
if (!args || !Array.isArray(args)) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const arg of args) {
|
||||
if (typeof arg === 'string') {
|
||||
// Check if any argument looks like it's trying to execute a shell command
|
||||
const suspiciousArg = arg.toLowerCase().trim()
|
||||
if (
|
||||
suspiciousArg.startsWith('/bin/') ||
|
||||
suspiciousArg.startsWith('/usr/bin/') ||
|
||||
suspiciousArg.includes('sh') ||
|
||||
suspiciousArg.includes('bash') ||
|
||||
suspiciousArg.includes('cmd') ||
|
||||
suspiciousArg.includes('powershell')
|
||||
) {
|
||||
throw new Error(`Security Error: Argument "${arg}" contains potentially dangerous command references and is not allowed.`)
|
||||
}
|
||||
|
||||
// Check for shell injection attempts in arguments
|
||||
if (
|
||||
suspiciousArg.includes('&&') ||
|
||||
suspiciousArg.includes('||') ||
|
||||
suspiciousArg.includes(';') ||
|
||||
suspiciousArg.includes('`') ||
|
||||
suspiciousArg.includes('$(') ||
|
||||
suspiciousArg.includes('${')
|
||||
) {
|
||||
throw new Error(`Security Error: Argument "${arg}" contains potentially dangerous shell operators and is not allowed.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Supergateway_MCP implements INode {
|
||||
label: string
|
||||
name: string
|
||||
|
|
@ -90,11 +220,7 @@ class Supergateway_MCP implements INode {
|
|||
const _args = nodeData.inputs?.arguments as string
|
||||
const packagePath = getNodeModulesPackagePath('supergateway/dist/index.js')
|
||||
|
||||
const serverParams = {
|
||||
command: 'node',
|
||||
args: [
|
||||
packagePath,
|
||||
..._args
|
||||
const processedArgs = _args
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.map((arg) => {
|
||||
|
|
@ -104,7 +230,22 @@ class Supergateway_MCP implements INode {
|
|||
}
|
||||
return arg
|
||||
})
|
||||
]
|
||||
|
||||
// Security validation: Check for dangerous arguments
|
||||
// TODO: To be removed and only allow Remote MCP for Cloud
|
||||
if (process.env.CUSTOM_MCP_SECURITY_CHECK === 'true') {
|
||||
validateArguments(processedArgs)
|
||||
}
|
||||
|
||||
const serverParams = {
|
||||
command: 'node',
|
||||
args: [packagePath, ...processedArgs]
|
||||
}
|
||||
|
||||
// Security validation: Check for dangerous commands
|
||||
// TODO: To be removed and only allow Remote MCP for Cloud
|
||||
if (process.env.CUSTOM_MCP_SECURITY_CHECK === 'true') {
|
||||
validateCommand(serverParams.command)
|
||||
}
|
||||
|
||||
const toolkit = new MCPToolkit(serverParams, 'stdio')
|
||||
|
|
|
|||
Loading…
Reference in New Issue