DevSecOps & Supply Chain
Notion MCP: prompt injection, permissões e defesa técnica
Riscos documentados do Notion MCP: páginas não confiáveis, autorização por ação, ferramentas de escrita e laboratório sem acesso externo.
Conectar um assistente ao Notion por MCP transforma páginas em entradas para um sistema capaz de consultar e alterar dados. O risco mais interessante não exige que a página execute JavaScript: texto comum pode tentar influenciar o assistente a realizar uma ação que o usuário não autorizou. A documentação oficial reconhece essa superfície de prompt injection.
Não foi encontrada, nas fontes primárias consultadas, uma CVE recente confirmada do aplicativo Notion que sustente uma alegação de invasão do produto. Este artigo trata do risco documentado de integração MCP. Mantém separados o comportamento do conector, a decisão do cliente e os dados armazenados no workspace.
O alerta oficial de segurança de MCP
As práticas de segurança do Notion MCP explicam que um cliente pode obter acesso a conteúdo e ferramentas de acordo com permissões concedidas. Também alertam para instruções maliciosas em conteúdo e para a necessidade de revisar clientes, acessos e ações.
O repositório oficial do servidor local informa que essa implementação deixou de ser mantida e suportada ativamente, recomendando a alternativa remota oficial. Isso é informação de suporte. Não é, por si só, uma CVE nem prova de que toda instalação existente foi comprometida.
| Elemento | Responsabilidade de segurança |
|---|---|
| Página consultada | Dado potencialmente não confiável |
| Cliente MCP | Política de ferramentas e consentimento |
| Autorização | Limites de acesso concedidos pelo usuário |
| Ferramenta de escrita | Ação com efeitos verificáveis |
| Logs | Registro sem credenciais e com contexto |
Como dados se tornam uma instrução indevida
Considere uma página fictícia de fornecedores que inclua um trecho ordenando ao assistente copiar dados de outra página para um destino externo. A pessoa pediu um resumo, não essa transferência. Se o sistema tratar o texto recebido como uma instrução com a mesma autoridade do pedido humano, cruza uma fronteira de confiança.
O ataque depende da combinação entre conteúdo controlado, ferramentas disponíveis e política do cliente. Um conteúdo hostil em uma página não prova que houve exfiltração. Para demonstrar impacto, seria preciso observar a ação indevida e quais dados a ferramenta podia realmente alcançar, em ambiente autorizado.
Separar visualmente a instrução em uma tag não é uma garantia suficiente. O controle decisivo deve existir fora da geração de texto: o host valida a ação, o objeto, o destino e o consentimento antes de executá-la. A segurança não pode depender apenas de o modelo lembrar uma recomendação.
Autorização por operação e por objeto
Uma permissão genérica de “usar Notion” é ampla demais para expressar todos os efeitos. Ler uma página, criar outra, alterar uma propriedade e compartilhar conteúdo devem possuir políticas diferentes. Cada solicitação precisa identificar os objetos e preservar a relação com o propósito aprovado pelo usuário.
Também importa o conjunto de ferramentas disponível na mesma sessão. Um conector de leitura, combinado com um segundo conector capaz de enviar dados, pode criar um caminho de transferência que nenhum deles apresenta isoladamente. A revisão deve analisar a composição e o contexto de dados, não somente cada lista de permissões separada.
Credenciais não devem aparecer em resultados ou mensagens. Use referências mantidas pelo host e trate páginas privadas com classificação herdada. Exportações, observabilidade e caches precisam respeitar essa mesma política. Um relatório de erro não pode se tornar um caminho alternativo de vazamento.
Laboratório: aprovação vinculada à ação exata
O exemplo calcula um hash canônico da ação e exige que a aprovação venha do usuário. Tudo ocorre localmente, com uma página inventada. Nenhuma API do Notion é chamada e o hash não é uma assinatura digital.
import hashlib
import json
def resumo(acao):
return hashlib.sha256(json.dumps(acao,sort_keys=True,separators=(',',':')).encode()).hexdigest()
acao = {'operacao':'atualizar_pagina','pagina':'pagina-ficticia','conteudo':'Resumo revisado'}
aprovacao = {'ator':'usuario','hash':resumo(acao)}
def autorizado(pedido, consentimento):
return consentimento.get('ator') == 'usuario' and consentimento.get('hash') == resumo(pedido)
alterada = dict(acao,conteudo='Outro conteudo')
assert autorizado(acao,aprovacao)
assert not autorizado(alterada,aprovacao)
assert not autorizado(acao,{'ator':'conteudo_da_pagina','hash':resumo(acao)})
print(json.dumps({'aprovacao_vinculada':True,'alteracao_recusada':True,'pagina_nao_aprova':True}))
O consentimento permite a ação original, mas deixa de permitir a mesma operação com conteúdo alterado. Uma suposta aprovação proveniente de conteudo_da_pagina é recusada. Isso demonstra duas propriedades: a origem da autorização importa e a autorização precisa corresponder ao efeito que será executado.
Em produção, o consentimento deve ser emitido por uma interface confiável, armazenado fora do conteúdo e protegido contra adulteração. Adicione identidade, prazo, sessão e mecanismos contra repetição. Um campo ator entregue pela própria extensão não pode provar que um humano aprovou; o modelo só ilustra o contrato.
Matriz de testes para uma integração profissional
| Caso | Resultado esperado |
|---|---|
| Página pede ação fora do pedido humano | Não executar |
| Escrita aprovada sofre alteração | Solicitar nova revisão |
| Objeto não autorizado | Recusar antes de chamar a API |
| Credencial revogada durante a tarefa | Encerrar acesso e descartar callbacks |
| Conteúdo privado chega ao exportador | Aplicar a mesma restrição |
Use duas páginas de laboratório com permissões distintas e um destino de saída fictício. Registre o pedido humano, o conteúdo consultado, a ferramenta proposta e a decisão do host. Preserve apenas dados necessários para comprovar o resultado. Não teste uma hipótese usando páginas de terceiros ou conteúdo real de colegas sem autorização.
Uma boa evidência inclui o caso negativo: a tentativa chegou ao host e foi recusada sem efeito. Mostrar apenas uma tela dizendo “bloqueado” não comprova que uma operação assíncrona não saiu em segundo plano. Observe o ponto de execução e a ausência de chamada externa.
Hardening e manutenção
Conceda o menor conjunto de páginas e ações necessário. Separe tarefas de leitura de tarefas de escrita e exija revisão humana quando houver alteração ou compartilhamento. Mantenha um inventário de clientes autorizados e um procedimento de revogação, seguindo a orientação de segurança e privacidade do Notion.
Avalie retenção de tokens, redirecionamento de autorização, confiabilidade do cliente e tratamento de respostas. Um cliente não confiável pode usar corretamente uma autorização OAuth e ainda produzir consequências indevidas. O protocolo confirma determinados vínculos; não julga sozinho a intenção da ação solicitada.
Perguntas frequentes
Isso é uma CVE do Notion? Não é essa a alegação. Trata-se de uma classe de risco descrita pelo fornecedor para integrações MCP.
Só texto pode causar um problema? Pode, se uma decisão posterior converter esse texto em uma operação autorizada indevidamente. O impacto ocorre na execução da ferramenta.
Um hash torna o fluxo seguro? Não sozinho. A confiança exige origem autenticada do consentimento e aplicação da política pelo host.
O objetivo de um conector robusto é permitir trabalho útil sem deixar uma página decidir os próprios privilégios. Dados consultados podem informar a tarefa, mas a autorização deve permanecer ligada ao usuário, ao objeto e ao efeito concreto.