In this article
Como criar servidores MCP seguros: guia para desenvolvedores evitarem vulnerabilidades críticas
O Model Context Protocol (MCP) rapidamente se tornou o padrão de fato para ampliar os recursos da IA. Desde o anúncio da Anthropic, em novembro de 2024, desenvolvedores têm se apressado para criar servidores MCP que conectam LLMs a bancos de dados, sistemas de arquivos, APIs e ferramentas de linha de comando. No entanto, na corrida para liberar a autonomia da IA, a segurança muitas vezes ficou em segundo plano, enquanto cresce a conscientização sobre as consequências previsíveis disso.
A realidade é contundente: servidores MCP são simplesmente mais código, e mais código significa mais bugs, uma superfície de ataque maior e mais vulnerabilidades de segurança. O que torna o MCP particularmente perigoso é o contexto em que esses servidores operam. Eles são executados em máquinas de desenvolvedores que contêm chaves de API, credenciais e propriedade intelectual. São controlados por agentes de IA que podem ser manipulados por meio de injeção de prompt (inclusive indireta). E muitas vezes são lançados com a mesma classe de vulnerabilidades que afeta aplicações web há décadas.
Este guia examina as vulnerabilidades críticas que afetam os servidores MCP hoje, incluindo injeção de comandos, path traversal e injeção de SQL, com base em CVEs reais e pesquisas de segurança. Você vai aprender não apenas como essas vulnerabilidades se manifestam, mas também como criar servidores MCP que resistam a elas desde o início.

Injeção de comandos: a vulnerabilidade mais comum em MCP
A injeção de comandos é uma das vulnerabilidades mais frequentemente encontradas em servidores MCP. O padrão é preocupantemente familiar: um servidor MCP inicia comandos do sistema, como npm, git ou lsof, e incorpora entradas controladas pelo usuário sem a sanitização adequada.
Você pode pensar nisso pela perspectiva da injeção de prompt, mas trata-se de um prompt malicioso que, no fim, leva à execução remota de comandos.
Entenda a vulnerabilidade
Considere um servidor MCP aparentemente inofensivo que consulta informações de pacotes npm:
server.tool(
"getNpmPackageInfo",
"Get information about an npm package",
{ packageName: z.string() },
async ({ packageName }) => {
const output = execSync(`npm view ${packageName}`, {
encoding: "utf-8",
});
return {
content: [{ type: "text", text: output }],
};
}
);A vulnerabilidade é sutil, mas grave. O parâmetro packageName vai diretamente para um comando do shell por meio de interpolação de strings. Quando alguém pergunta ao assistente de IA: "Qual é a data do último lançamento de react; touch /tmp/pwned?", o comando se torna:
npm view react; touch /tmp/pwnedO ponto e vírgula encerra o primeiro comando, e o shell executa sem hesitar touch /tmp/pwned como um comando separado. Um invasor que controla o prompt agora consegue executar comandos arbitrários na máquina do desenvolvedor.
Prompts podem se transformar em responsabilidade por CVEs reais
Isso não é teoria. Vários servidores MCP foram identificados com vulnerabilidades de injeção de comandos:
O GitHub Kanban MCP Server (GHSA-6jx8-rcjx-vmwf) não sanitizava as entradas dos usuários, permitindo a execução de comandos arbitrários por meio de operações do Git
O iOS Simulator MCP Server (GHSA-6f6r-m9pv-67jw) expunha vulnerabilidades semelhantes
O pacote Create MCP Server STDIO continha definições de ferramentas com falhas, expondo o monitoramento do sistema a ataques de injeção

A correção de segurança: use a API segura do Node.js execFile em vez de exec
A função exec do Node.js inicia um shell e executa comandos nele, tornando perigosos metacaracteres do shell como ;, | e $(). A função execFile executa arquivos diretamente, sem interpretação pelo shell:
// VULNERABLE: Uses shell interpolation
execSync(`npm view ${packageName}`);
// SECURE: Arguments passed as array, no shell
execFile('npm', ['view', packageName], (error, stdout) => {
// handle result
});Veja uma implementação segura:
import { execFile } from 'child_process';
server.tool(
"getNpmPackageInfo",
{ packageName: z.string() },
async ({ packageName }) => {
return new Promise((resolve, reject) => {
execFile('npm', ['view', packageName], { encoding: 'utf-8' },
(error, stdout) => {
if (error) reject(error);
resolve({
content: [{ type: "text", text: stdout }],
});
}
);
});
}
);Com execFile, a entrada maliciosa react; touch /tmp/pwned se torna um único argumento passado para npm view, que falha de forma segura em vez de executar comandos arbitrários.
Outras medidas para evitar injeção de comandos
Valide as entradas usando listas de permissões: se estiver esperando nomes de pacotes, valide-os de acordo com as convenções de nomenclatura do npm
Separe os comandos dos argumentos: use APIs seguras para evitar injeção de comandos, dando preferência a
execFileem vez deexecEscape os argumentos do shell: quando não for possível evitar a execução pelo shell, use bibliotecas como
shell-quoteUse APIs específicas da linguagem: em vez de iniciar
npm, use diretamente a API do registro npmDefina limites para o tamanho das entradas: entradas incomumente longas costumam indicar tentativas de injeção

Path traversal: como escapar do sandbox
Servidores MCP frequentemente expõem operações de sistema de arquivos, como ler arquivos de configuração, acessar documentação ou disponibilizar recursos estáticos. As vulnerabilidades de path traversal ocorrem quando invasores manipulam caminhos de arquivos para acessar arquivos fora do diretório previsto.
O padrão da vulnerabilidade no código do servidor MCP
Um padrão comum em manipuladores de recursos MCP:
server.resource(
"pipeline-workflows",
new ResourceTemplate("pipeline-workflows://{name}", { list: undefined }),
async (uri, { name }) => {
const decodedName = decodeURIComponent(name);
let filePath = path.resolve(
process.cwd(),
'.github/workflows/',
`${decodedName}.yaml`
);
const fileContents = readFileSync(filePath, 'utf-8');
return {
contents: [{ uri: uri.href, text: fileContents }]
};
}
);Um invasor pode solicitar pipeline-workflows://../../../../../../etc/passwd, e o servidor lerá /etc/passwd prontamente. Em uma máquina de desenvolvedor, alvos ainda mais valiosos incluem:
~/.ssh/id_rsa(chaves privadas SSH)~/.aws/credentials(chaves de acesso da AWS)arquivos
.env(segredos de aplicações)~/.npmrc(tokens de autenticação do npm)
Estudo de caso: framework Mastra AI vulnerável a path traversal
O pacote @mastra/mcp-docs-server continha uma vulnerabilidade sutil de path traversal. Embora o código incluísse uma verificação de segurança, a execução continuava mesmo após a detecção de uma tentativa de traversal:
async function readMdxContent(docPath, queryKeywords) {
const fullPath = path.resolve(path.join(docsBaseDir, docPath));
// Security check exists...
if (!fullPath.startsWith(path.resolve(docsBaseDir))) {
logger.error(`Path traversal attempt detected`);
return { found: false };
}
// ...
}
execute: async (args) => {
const result = await readMdxContent(path, queryKeywords);
if (result.found) {
return { /* ... */ };
}
// VULNERABILITY: Executes even after traversal detection!
const directorySuggestions = await findNearestDirectory(path, availablePaths);
// ...
}A função findNearestDirectory operava sobre o caminho não validado, expondo listagens de diretórios fora do escopo previsto.
Como tratar caminhos com segurança nos recursos do servidor MCP
Adote uma estratégia de defesa em profundidade para operações com arquivos:
import path from 'path';
import { accessSync, readFileSync, constants } from 'fs';
function secureFilePath(baseDir, userPath) {
// Normalize and resolve the full path
const normalizedBase = path.resolve(baseDir);
const requestedPath = path.resolve(baseDir, userPath);
// Verify the path stays within bounds
if (!requestedPath.startsWith(normalizedBase + path.sep)) {
throw new Error('Path traversal detected');
}
// Verify the file exists and is readable
accessSync(requestedPath, constants.R_OK);
return requestedPath;
}
server.resource(
"docs",
new ResourceTemplate("docs://{filename}", { list: undefined }),
async (uri, { filename }) => {
const baseDir = path.resolve(process.cwd(), 'docs');
// Halt execution immediately on invalid paths
const safePath = secureFilePath(baseDir, filename);
const contents = readFileSync(safePath, 'utf-8');
return {
contents: [{ uri: uri.href, text: contents }]
};
}
);Lista de verificação para evitar path traversal
Sempre resolva os caminhos: use
path.resolve()para converter caminhos relativos em absolutosValide o resultado: confirme que os caminhos resolvidos começam com o diretório-base previsto
Rejeite imediatamente: nunca continue o processamento após detectar tentativas de traversal
Use listas de permissões: sempre que possível, restrinja o acesso a arquivos explicitamente autorizados
Evite extensões controladas pelo usuário: não permita que usuários especifiquem extensões de arquivos

Injeção de SQL: a ilusão do "somente leitura"
À medida que os servidores MCP ampliam a conectividade com bancos de dados, as vulnerabilidades de injeção de SQL se tornam uma preocupação crítica. Mais preocupante ainda: muitos servidores MCP de banco de dados implementam um modo "somente leitura" falho, que transmite uma falsa sensação de segurança.
A verificação ingênua de somente leitura
Vários servidores MCP de banco de dados tentam impor acesso somente leitura verificando se as consultas começam com SELECT:
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const query = request.params.arguments?.query;
if (!query.trim().toLowerCase().startsWith("select")) {
throw new Error("Only SELECT queries are allowed");
}
const result = await client.query(query);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
});Essa abordagem falha de forma catastrófica diante das inúmeras funções integradas do PostgreSQL.
Como contornar restrições inseguras de somente leitura em servidores MCP
O PostgreSQL oferece funções administrativas que podem ser chamadas em instruções SELECT:
-- Denial of Service: Terminate database connections
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE usename != 'admin';
-- Long-running resource exhaustion
SELECT pg_sleep(300);
-- Information disclosure: Expose all running queries
SELECT pid, usename, query FROM pg_stat_activity;
-- Configuration extraction
SELECT name, setting FROM pg_settings WHERE name LIKE '%password%';
-- Force checkpoint (performance disruption)
SELECT pg_start_backup('malicious_backup', true);
Estudo de caso: vulnerabilidades reais em servidores MCP exploradas por meio de injeção de SQL
No Xata's MCP Server, que não recebeu um CVE oficial, era possível contornar a transação somente leitura do servidor:
COMMIT; INSERT INTO users (name) VALUES ('attacker');Ao encerrar a transação somente leitura com COMMIT, os invasores conseguiam executar operações de gravação.
O ExecuteAutomation Database Server (CVE-2025-59333): controles de acesso igualmente falhos permitiam encadear consultas:
SELECT * FROM users; DROP TABLE users; --Como implementar acesso seguro a bancos de dados em servidores MCP?
Exija a execução de uma única consulta:
// Force prepared statement (prevents multi-query)
const result = await client.query({
name: "single-query",
text: userQuery,
values: [],
});Use permissões no nível do banco de dados:
-- Create restricted user
CREATE USER mcp_readonly WITH PASSWORD 'secure_password';
-- Grant only SELECT on specific tables
GRANT SELECT ON public.users TO mcp_readonly;
GRANT SELECT ON public.products TO mcp_readonly;
-- Revoke dangerous function access
REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM mcp_readonly;Implemente listas de permissões para consultas:
const ALLOWED_QUERIES = {
"get_users": "SELECT id, name FROM users WHERE active = $1",
"get_products": "SELECT id, name, price FROM products WHERE category = $1"
};
server.tool("query_database", { queryName: z.string(), params: z.array(z.any()) },
async ({ queryName, params }) => {
const query = ALLOWED_QUERIES[queryName];
if (!query) throw new Error("Query not permitted");
return await client.query(query, params);
}
);Bloqueie funções perigosas:
const DANGEROUS_PATTERNS = [
/pg_\w+\(/i, // PostgreSQL system functions
/\bcopy\b/i, // COPY command
/\binto\s+outfile/i, // File operations
/\bload_file\b/i, // File loading
/\bexecute\b/i, // Dynamic execution
/\bsleep\b/i, // Sleep-based DoS
];
function validateQuery(query) {
for (const pattern of DANGEROUS_PATTERNS) {
if (pattern.test(query)) {
throw new Error("Query contains prohibited patterns");
}
}
}Use recursos MCP para acesso estruturado:
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const resourceUrl = new URL(request.params.uri);
const [schema, tableName] = resourceUrl.pathname.split('/').filter(Boolean);
// Validate against allowlist
if (!ALLOWED_TABLES.includes(tableName)) {
throw new Error('Table not permitted');
}
// Use parameterized query
const result = await client.query(
'SELECT * FROM information_schema.columns WHERE table_name = $1',
[tableName]
);
return { contents: [{ uri: request.params.uri, text: JSON.stringify(result) }] };
});
Proteja dependências de terceiros
Servidores MCP dependem de pacotes npm para drivers de banco de dados, clientes HTTP e funções utilitárias. Cada dependência representa um possível risco à cadeia de suprimentos:
Dependências vulneráveis: CVEs conhecidas em pacotes como
pg,axiosoulodashPacotes maliciosos: ataques de typosquatting direcionados a desenvolvedores de servidores MCP
Vulnerabilidades transitivas: falhas de segurança nas dependências das dependências
Estratégias de mitigação
Faça varreduras contínuas: integre o Snyk ou ferramentas semelhantes ao pipeline de CI/CD para detectar dependências vulneráveis antes da implantação
Fixe as versões das dependências: use arquivos de lock (
package-lock.json) e verifique a integridadeAtualize regularmente: acompanhe os avisos de segurança e aplique correções sem demora
Minimize as dependências: cada pacote amplia a superfície de ataque; avalie se ele é realmente necessário no seu servidor MCP.
Faça uma auditoria antes de adotar: consulte as pontuações de integridade dos pacotes no Snyk Security Database
Ações recomendadas: como criar servidores MCP seguros

Para desenvolvedores de servidores MCP
Valide todas as entradas: nunca confie em dados provenientes de chamadas de ferramentas geradas por LLMs
Use APIs seguras: prefira
execFileaexece consultas parametrizadas à interpolação de stringsAdote uma estratégia de defesa em profundidade: use várias camadas de validação, não apenas uma verificação
Integre ferramentas SAST: use o Snyk Code ou ferramentas semelhantes para identificar vulnerabilidades durante o desenvolvimento
Aplique o princípio do menor privilégio: limite ao mínimo necessário os escopos de usuários de bancos de dados, acesso ao sistema de arquivos e permissões de rede
Documente o modelo de segurança: deixe explícitos os limites de confiança e as premissas
Para usuários de servidores MCP
Faça uma auditoria antes de instalar: revise o código-fonte, especialmente os manipuladores de ferramentas
Monitore o comportamento: fique de olho em acessos inesperados a arquivos, solicitações de rede ou execução de comandos
Isole os ambientes: execute servidores MCP em ambientes sandbox
Mantenha tudo atualizado: aplique as correções de segurança sem demora
Reporte vulnerabilidades: pratique a divulgação responsável ao encontrar problemas
Para organizações
Estabeleça políticas para MCP: defina os servidores aprovados e os requisitos de segurança
Implemente varreduras: faça a varredura automática do código do servidor MCP antes da implantação
Capacite os desenvolvedores: ensine às equipes práticas de desenvolvimento seguro para MCP
Monitore e audite: registre a atividade do servidor MCP para análise de segurança
O caminho a seguir
O Model Context Protocol representa um paradigma poderoso para ampliar os recursos da IA, mas poder traz responsabilidade. As vulnerabilidades que analisamos — injeção de comandos, path traversal e injeção de SQL — não são novidades. São as mesmas falhas que afetam aplicações web há décadas, agora em um novo contexto e com impacto potencialmente maior.
A ironia é evidente: na pressa para tornar a IA mais capaz, nós a conectamos a sistemas construídos sobre as mesmas bases frágeis que há anos tentamos proteger. Um LLM com acesso a um servidor MCP vulnerável se torna um vetor de ataque involuntário, com sua inteligência transformada em arma por uma simples manipulação de strings.

O caminho a seguir exige que tratemos o desenvolvimento de servidores MCP com o mesmo rigor aplicado a qualquer código crítico para a segurança. Valide as entradas. Use APIs seguras. Adote uma estratégia de defesa em profundidade. Faça varreduras em busca de vulnerabilidades. E lembre-se: "somente leitura" muitas vezes é uma ilusão perigosa.
As ferramentas para criar servidores MCP seguros já existem. A questão é se vamos usá-las antes que a próxima onda de vulnerabilidades vire notícia.
Quer entender os novos vetores de ataque a servidores MCP — de envenenamento e sombreamento de ferramentas a fluxos tóxicos? Analise incidentes reais e aprenda a se defender com estratégias práticas que consideram o fluxo completo no eBook Securing The MCP Servers Ecosystem.
Participe do Fetch the Flag 2026!
Teste suas habilidades, resolva desafios e domine o placar. Junte-se a nós de 12h ET de 12 de fevereiro a 12h ET de 13 de fevereiro para o evento CTF definitivo.