add validateMCPServerSecurity
This commit is contained in:
parent
ca3818913e
commit
6669c8ffcc
|
|
@ -1,105 +1,10 @@
|
||||||
import { Tool } from '@langchain/core/tools'
|
import { Tool } from '@langchain/core/tools'
|
||||||
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../../src/Interface'
|
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../../src/Interface'
|
||||||
import { MCPToolkit } from '../core'
|
import { MCPToolkit, validateMCPServerSecurity } from '../core'
|
||||||
import { getVars, prepareSandboxVars } from '../../../../src/utils'
|
import { getVars, prepareSandboxVars } from '../../../../src/utils'
|
||||||
import { DataSource } from 'typeorm'
|
import { DataSource } from 'typeorm'
|
||||||
import hash from 'object-hash'
|
import hash from 'object-hash'
|
||||||
|
|
||||||
// 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.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mcpServerConfig = `{
|
const mcpServerConfig = `{
|
||||||
"command": "npx",
|
"command": "npx",
|
||||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
|
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
|
||||||
|
|
@ -264,33 +169,8 @@ class Custom_MCP implements INode {
|
||||||
serverParams = JSON.parse(serverParamsString)
|
serverParams = JSON.parse(serverParamsString)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Security validation: Check for dangerous commands
|
if (process.env.CUSTOM_MCP_SECURITY_CHECK === 'true') {
|
||||||
// TODO: To be removed and only allow Remote MCP for Cloud
|
validateMCPServerSecurity(serverParams)
|
||||||
if (serverParams?.command && process.env.CUSTOM_MCP_SECURITY_CHECK === 'true') {
|
|
||||||
validateCommand(serverParams.command)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also validate any commands in args that might be suspicious
|
|
||||||
// TODO: To be removed and only allow Remote MCP for Cloud
|
|
||||||
if (serverParams?.args && Array.isArray(serverParams.args) && process.env.CUSTOM_MCP_SECURITY_CHECK === 'true') {
|
|
||||||
for (const arg of serverParams.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.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compatible with stdio and SSE
|
// Compatible with stdio and SSE
|
||||||
|
|
|
||||||
|
|
@ -1,137 +1,7 @@
|
||||||
import { Tool } from '@langchain/core/tools'
|
import { Tool } from '@langchain/core/tools'
|
||||||
import { ICommonObject, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../../src/Interface'
|
import { ICommonObject, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../../src/Interface'
|
||||||
import { getNodeModulesPackagePath } from '../../../../src/utils'
|
import { getNodeModulesPackagePath } from '../../../../src/utils'
|
||||||
import { MCPToolkit } from '../core'
|
import { MCPToolkit, validateMCPServerSecurity } 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 {
|
class Supergateway_MCP implements INode {
|
||||||
label: string
|
label: string
|
||||||
|
|
@ -231,21 +101,17 @@ class Supergateway_MCP implements INode {
|
||||||
return arg
|
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 = {
|
const serverParams = {
|
||||||
command: 'node',
|
command: 'node',
|
||||||
args: [packagePath, ...processedArgs]
|
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') {
|
if (process.env.CUSTOM_MCP_SECURITY_CHECK === 'true') {
|
||||||
validateCommand(serverParams.command)
|
try {
|
||||||
|
validateMCPServerSecurity(serverParams)
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Security validation failed: ${error.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolkit = new MCPToolkit(serverParams, 'stdio')
|
const toolkit = new MCPToolkit(serverParams, 'stdio')
|
||||||
|
|
|
||||||
|
|
@ -173,3 +173,400 @@ function createSchemaModel(
|
||||||
|
|
||||||
return z.object(schemaProperties)
|
return z.object(schemaProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: To be removed and only allow Remote MCP for Cloud
|
||||||
|
* Validates MCP server configuration to prevent execution of dangerous commands
|
||||||
|
*/
|
||||||
|
export function validateMCPServerSecurity(serverParams: any): void {
|
||||||
|
// Comprehensive list of dangerous commands that could compromise system security
|
||||||
|
const dangerousCommands = [
|
||||||
|
// Shell interpreters and command processors
|
||||||
|
'sh',
|
||||||
|
'bash',
|
||||||
|
'zsh',
|
||||||
|
'fish',
|
||||||
|
'csh',
|
||||||
|
'tcsh',
|
||||||
|
'ksh',
|
||||||
|
'ash',
|
||||||
|
'dash',
|
||||||
|
'cmd',
|
||||||
|
'command',
|
||||||
|
'powershell',
|
||||||
|
'pwsh',
|
||||||
|
'cmd.exe',
|
||||||
|
'powershell.exe',
|
||||||
|
'wsl',
|
||||||
|
'wsl.exe',
|
||||||
|
'ubuntu',
|
||||||
|
'debian',
|
||||||
|
|
||||||
|
// File operations that could read/write sensitive files
|
||||||
|
'cat',
|
||||||
|
'more',
|
||||||
|
'less',
|
||||||
|
'head',
|
||||||
|
'tail',
|
||||||
|
'tee',
|
||||||
|
'cp',
|
||||||
|
'mv',
|
||||||
|
'rm',
|
||||||
|
'del',
|
||||||
|
'copy',
|
||||||
|
'move',
|
||||||
|
'type',
|
||||||
|
'ren',
|
||||||
|
'rename',
|
||||||
|
'ln',
|
||||||
|
'link',
|
||||||
|
'unlink',
|
||||||
|
'touch',
|
||||||
|
'mkdir',
|
||||||
|
'rmdir',
|
||||||
|
'rd',
|
||||||
|
'md',
|
||||||
|
'makedir',
|
||||||
|
|
||||||
|
// Directory operations and file system navigation
|
||||||
|
'ls',
|
||||||
|
'dir',
|
||||||
|
'pwd',
|
||||||
|
'cd',
|
||||||
|
'find',
|
||||||
|
'locate',
|
||||||
|
'tree',
|
||||||
|
'du',
|
||||||
|
'df',
|
||||||
|
'pushd',
|
||||||
|
'popd',
|
||||||
|
'dirs',
|
||||||
|
'whereis',
|
||||||
|
'which',
|
||||||
|
'where',
|
||||||
|
'stat',
|
||||||
|
|
||||||
|
// Network operations that could exfiltrate data or download malicious content
|
||||||
|
'curl',
|
||||||
|
'wget',
|
||||||
|
'nc',
|
||||||
|
'netcat',
|
||||||
|
'ping',
|
||||||
|
'nslookup',
|
||||||
|
'dig',
|
||||||
|
'host',
|
||||||
|
'telnet',
|
||||||
|
'ssh',
|
||||||
|
'scp',
|
||||||
|
'rsync',
|
||||||
|
'ftp',
|
||||||
|
'sftp',
|
||||||
|
'icat',
|
||||||
|
'socat',
|
||||||
|
|
||||||
|
// System operations and process management
|
||||||
|
'ps',
|
||||||
|
'top',
|
||||||
|
'htop',
|
||||||
|
'kill',
|
||||||
|
'killall',
|
||||||
|
'pkill',
|
||||||
|
'pgrep',
|
||||||
|
'jobs',
|
||||||
|
'systemctl',
|
||||||
|
'service',
|
||||||
|
'chkconfig',
|
||||||
|
'update-rc.d',
|
||||||
|
'systemd',
|
||||||
|
'crontab',
|
||||||
|
'at',
|
||||||
|
'batch',
|
||||||
|
'nohup',
|
||||||
|
'screen',
|
||||||
|
'tmux',
|
||||||
|
|
||||||
|
// Archive operations that could be used for data exfiltration
|
||||||
|
'tar',
|
||||||
|
'zip',
|
||||||
|
'unzip',
|
||||||
|
'gzip',
|
||||||
|
'gunzip',
|
||||||
|
'bzip2',
|
||||||
|
'bunzip2',
|
||||||
|
'xz',
|
||||||
|
'unxz',
|
||||||
|
'7z',
|
||||||
|
'rar',
|
||||||
|
'unrar',
|
||||||
|
'compress',
|
||||||
|
'uncompress',
|
||||||
|
'cpio',
|
||||||
|
'ar',
|
||||||
|
|
||||||
|
// Text processing tools that could read sensitive files
|
||||||
|
'grep',
|
||||||
|
'awk',
|
||||||
|
'sed',
|
||||||
|
'sort',
|
||||||
|
'uniq',
|
||||||
|
'cut',
|
||||||
|
'tr',
|
||||||
|
'wc',
|
||||||
|
'diff',
|
||||||
|
'patch',
|
||||||
|
'strings',
|
||||||
|
'hexdump',
|
||||||
|
'od',
|
||||||
|
'xxd',
|
||||||
|
'base64',
|
||||||
|
'base32',
|
||||||
|
|
||||||
|
// File editors that could modify system files
|
||||||
|
'vi',
|
||||||
|
'vim',
|
||||||
|
'nano',
|
||||||
|
'emacs',
|
||||||
|
'gedit',
|
||||||
|
'notepad',
|
||||||
|
'notepad.exe',
|
||||||
|
'pico',
|
||||||
|
'joe',
|
||||||
|
'micro',
|
||||||
|
'code',
|
||||||
|
'subl',
|
||||||
|
'atom',
|
||||||
|
|
||||||
|
// Process execution and evaluation commands
|
||||||
|
'exec',
|
||||||
|
'eval',
|
||||||
|
'system',
|
||||||
|
'spawn',
|
||||||
|
'fork',
|
||||||
|
'clone',
|
||||||
|
'source',
|
||||||
|
'sudo',
|
||||||
|
'su',
|
||||||
|
'runuser',
|
||||||
|
'doas',
|
||||||
|
'pfexec',
|
||||||
|
|
||||||
|
// Package managers that could install malicious software
|
||||||
|
'npm',
|
||||||
|
'yarn',
|
||||||
|
'pnpm',
|
||||||
|
'pip',
|
||||||
|
'pip3',
|
||||||
|
'apt',
|
||||||
|
'apt-get',
|
||||||
|
'yum',
|
||||||
|
'dnf',
|
||||||
|
'pacman',
|
||||||
|
'brew',
|
||||||
|
'choco',
|
||||||
|
'winget',
|
||||||
|
'scoop',
|
||||||
|
'snap',
|
||||||
|
'flatpak',
|
||||||
|
|
||||||
|
// Compilers and interpreters that could execute arbitrary code
|
||||||
|
'python',
|
||||||
|
'python3',
|
||||||
|
'nodejs',
|
||||||
|
'java',
|
||||||
|
'javac',
|
||||||
|
'gcc',
|
||||||
|
'g++',
|
||||||
|
'clang',
|
||||||
|
'clang++',
|
||||||
|
'ruby',
|
||||||
|
'perl',
|
||||||
|
'php',
|
||||||
|
'go',
|
||||||
|
'rust',
|
||||||
|
'cargo',
|
||||||
|
'dotnet',
|
||||||
|
'mono',
|
||||||
|
'scala',
|
||||||
|
'kotlin',
|
||||||
|
'swift',
|
||||||
|
|
||||||
|
// Database clients that could access sensitive data
|
||||||
|
'mysql',
|
||||||
|
'psql',
|
||||||
|
'mongo',
|
||||||
|
'mongosh',
|
||||||
|
'redis-cli',
|
||||||
|
'sqlite3',
|
||||||
|
'sqlcmd',
|
||||||
|
'isql',
|
||||||
|
'osql',
|
||||||
|
'bcp',
|
||||||
|
|
||||||
|
// Development and deployment tools
|
||||||
|
'git',
|
||||||
|
'docker',
|
||||||
|
'podman',
|
||||||
|
'kubectl',
|
||||||
|
'helm',
|
||||||
|
'terraform',
|
||||||
|
'ansible',
|
||||||
|
'vagrant',
|
||||||
|
'chef',
|
||||||
|
'puppet',
|
||||||
|
'saltstack',
|
||||||
|
'make',
|
||||||
|
'cmake',
|
||||||
|
|
||||||
|
// System information and configuration tools
|
||||||
|
'uname',
|
||||||
|
'whoami',
|
||||||
|
'id',
|
||||||
|
'groups',
|
||||||
|
'env',
|
||||||
|
'set',
|
||||||
|
'printenv',
|
||||||
|
'export',
|
||||||
|
'mount',
|
||||||
|
'umount',
|
||||||
|
'lsblk',
|
||||||
|
'fdisk',
|
||||||
|
'parted',
|
||||||
|
'lsmod',
|
||||||
|
'modprobe',
|
||||||
|
|
||||||
|
// File permissions and ownership commands
|
||||||
|
'chmod',
|
||||||
|
'chown',
|
||||||
|
'chgrp',
|
||||||
|
'umask',
|
||||||
|
'setfacl',
|
||||||
|
'getfacl',
|
||||||
|
'lsattr',
|
||||||
|
'chattr',
|
||||||
|
|
||||||
|
// Network configuration and monitoring
|
||||||
|
'ifconfig',
|
||||||
|
'ip',
|
||||||
|
'route',
|
||||||
|
'netstat',
|
||||||
|
'ss',
|
||||||
|
'lsof',
|
||||||
|
'tcpdump',
|
||||||
|
'wireshark',
|
||||||
|
'iptables',
|
||||||
|
'ufw',
|
||||||
|
'firewall-cmd',
|
||||||
|
|
||||||
|
// Boot and system control
|
||||||
|
'init',
|
||||||
|
'telinit',
|
||||||
|
'shutdown',
|
||||||
|
'reboot',
|
||||||
|
'halt',
|
||||||
|
'poweroff',
|
||||||
|
|
||||||
|
// Hardware and kernel interaction
|
||||||
|
'dmesg',
|
||||||
|
'lspci',
|
||||||
|
'lsusb',
|
||||||
|
'dmidecode',
|
||||||
|
'hdparm',
|
||||||
|
'smartctl'
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks a string for dangerous commands and patterns
|
||||||
|
* @param str - The string to check
|
||||||
|
* @param context - Context information for better error messages
|
||||||
|
*/
|
||||||
|
function checkString(str: string, context: string = ''): void {
|
||||||
|
if (typeof str !== 'string') return
|
||||||
|
|
||||||
|
const lowerStr = str.toLowerCase().trim()
|
||||||
|
const contextPrefix = context ? `${context}: ` : ''
|
||||||
|
|
||||||
|
for (const cmd of dangerousCommands) {
|
||||||
|
const cmdLower = cmd.toLowerCase()
|
||||||
|
// Escape special regex characters in command name
|
||||||
|
const escapedCmd = cmdLower.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||||
|
|
||||||
|
if (
|
||||||
|
lowerStr === cmdLower || // 1. Exact match: "cat" === "cat"
|
||||||
|
lowerStr.startsWith(cmdLower + ' ') || // 2. Command with space args: "cat /etc/passwd"
|
||||||
|
lowerStr.startsWith(cmdLower + '\t') || // 3. Command with tab args: "cat\t/etc/passwd"
|
||||||
|
lowerStr.endsWith('/' + cmdLower) || // 4. Unix absolute path: "/bin/sh"
|
||||||
|
lowerStr.includes('\\' + cmdLower + '.exe') || // 5. Windows executable: "C:\\Windows\\cmd.exe"
|
||||||
|
lowerStr.includes('/' + cmdLower + ' ') || // 6. Unix path with args: "/bin/sh -c"
|
||||||
|
lowerStr.includes('\\' + cmdLower + ' ') || // 7. Windows path with args: "C:\\bin\\sh.exe -c"
|
||||||
|
new RegExp(`\\b${escapedCmd}\\b`).test(lowerStr)
|
||||||
|
) {
|
||||||
|
// 8. Word boundary match: catches embedded commands
|
||||||
|
throw new Error(`${contextPrefix}Dangerous command detected: "${cmd}" in "${str}"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Check for null bytes (binary content or encoding attacks)
|
||||||
|
if (str.includes('\0')) {
|
||||||
|
throw new Error(`${contextPrefix}Null byte detected in string: "${str}"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively validates an object for dangerous content
|
||||||
|
* This function traverses the entire object tree to ensure no malicious content is hidden
|
||||||
|
* @param obj - The object to validate (can be string, array, object, or primitive)
|
||||||
|
* @param path - The current path in the object (for error reporting and debugging)
|
||||||
|
*/
|
||||||
|
function validateObject(obj: any, path: string = ''): void {
|
||||||
|
// Skip null/undefined values
|
||||||
|
if (obj === null || obj === undefined) return
|
||||||
|
|
||||||
|
if (typeof obj === 'string') {
|
||||||
|
// Validate string content for dangerous commands and patterns
|
||||||
|
checkString(obj, path)
|
||||||
|
} else if (Array.isArray(obj)) {
|
||||||
|
// Recursively validate each array element
|
||||||
|
obj.forEach((item, index) => {
|
||||||
|
validateObject(item, `${path}[${index}]`)
|
||||||
|
})
|
||||||
|
} else if (typeof obj === 'object') {
|
||||||
|
// Recursively validate each object property
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
const currentPath = path ? `${path}.${key}` : key
|
||||||
|
// Validate only the property value
|
||||||
|
validateObject(value, currentPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateObject(serverParams, 'serverParams')
|
||||||
|
|
||||||
|
if (serverParams.command) {
|
||||||
|
const cmd = serverParams.command.toLowerCase()
|
||||||
|
if (cmd.includes('sh') || cmd.includes('cmd') || cmd.includes('powershell') || cmd.includes('eval')) {
|
||||||
|
throw new Error(`Command field contains dangerous interpreter: "${serverParams.command}"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverParams.env) {
|
||||||
|
for (const [key, value] of Object.entries(serverParams.env)) {
|
||||||
|
if (typeof value === 'string' && (value.includes('$(') || value.includes('`'))) {
|
||||||
|
throw new Error(`Environment variable "${key}" contains command substitution: "${value}"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverParams.cwd) {
|
||||||
|
checkString(serverParams.cwd, 'cwd')
|
||||||
|
const cwd = serverParams.cwd.toLowerCase()
|
||||||
|
if (
|
||||||
|
cwd.startsWith('/bin') ||
|
||||||
|
cwd.startsWith('/sbin') ||
|
||||||
|
cwd.startsWith('/etc') ||
|
||||||
|
cwd.includes('system32') ||
|
||||||
|
cwd.includes('program files')
|
||||||
|
) {
|
||||||
|
throw new Error(`Working directory points to sensitive system location: "${serverParams.cwd}"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue