Segurança do servidor MCP para Craft CMS: o limite é um utilizador do Craft.
Um cliente de IA que pode alterar um site em funcionamento precisa de limites claros. Esta página lista cada limite pela ordem em que uma chamada o encontra. Diz também o que cada limite não cobre.
Por onde passa cada chamada
Por esta ordem. Uma chamada que falhe qualquer passo nunca chega à ferramenta.
- Limite de pedidos — chamadas por minuto, contadas por token. Um travão contra um modelo em ciclo, não uma defesa contra alguém determinado que tenha um token válido.
- Âmbito do token —
read,contentoufull. O âmbito só restringe o que o utilizador associado já pode fazer. - Edição — o plugin é distribuído numa única edição, por isso hoje este passo é sempre superado. Existe para que uma futura divisão em edições não possa disponibilizar uma ferramenta sem se dar por isso.
- Modo só de leitura — enquanto estiver ativo, nada que altere o estado é executado, digam o que disserem as definições abaixo.
- Ativação das ferramentas — todas as ferramentas que alteram o estado estão desligadas até um administrador as ativar, uma a uma.
- Verificação de administrador — as ferramentas de administrador exigem, além disso, que o utilizador associado seja administrador.
- Esquema dos argumentos — os argumentos são validados face ao esquema da ferramenta antes de a ferramenta os ver.
- Verificação de permissões do próprio Craft, por elemento — depois, a ferramenta pergunta ao Craft, para este elemento e este site, se o utilizador associado o pode ver, guardar ou eliminar.
Dois tipos de recusa, de propósito. Uma ferramenta que não existe e uma ferramenta que o âmbito do token não abrange recebem a mesma resposta — Unknown tool — porque a diferença diria a um atacante o que mais existe. Uma ferramenta desligada, bloqueada pelo modo só de leitura ou reservada a administradores também não é listada, mas uma chamada direta recebe o motivo por palavras simples, para que um operador não procure a falha do seu lado.
Porque é o utilizador o verdadeiro limite
Cada token pertence exatamente a um utilizador do Craft. São feitas duas perguntas, e a segunda é a que importa: primeiro a geral, se este tipo de ação está sequer aberto a este utilizador, e depois a precisa — pode este utilizador fazer isto, a este elemento, neste site. Um editor que só pode trabalhar num site e ver uma secção chega exatamente a isso através do cliente de IA, e a mais nada.
Isto tem uma consequência que vale a pena dizer claramente: um token que pertence a um administrador pode fazer o que um administrador pode fazer. Atribua a um token o utilizador com menos permissões que ainda consiga fazer o trabalho e use o âmbito para restringir ainda mais.
Uma secção ou um grupo de categorias desconhecido ou proibido devolve uma lista vazia, não um erro — um erro confirmaria que existe. Já um identificador de site que não existe é indicado como erro, porque um identificador errado é um engano na chamada, não um limite.
Tokens
- O texto simples é mostrado uma única vez, quando o token é criado. Só é guardado um hash SHA-256, por isso não pode ser mostrado de novo.
- Os tokens ficam numa tabela própria, nunca na configuração do projeto — que é enviada para o Git.
- A página de tokens no painel de controlo está aberta apenas a administradores. O Craft regista uma permissão «Access AlphaBridge MCP» para cada plugin com uma entrada na barra lateral; concedê-la não abre esta página a quem não é administrador.
- Um token pode ter uma data de expiração e pode ser revogado a qualquer momento; a chamada seguinte com ele falha.
- O cabeçalho
Authorizationé ocultado nas entradas de registo com o contexto do pedido do próprio Craft, por isso um token não acaba emstorage/logsquando um pedido é registado.
O registo de auditoria, e o que deliberadamente omite
Cada chamada de ferramenta é registada: quando, que ferramenta, que utilizador do Craft e o resultado — permitida, recusada ou falhada. As chamadas recusadas também são registadas; são as mais interessantes.
Os nomes dos argumentos são registados, os valores não. Consegue ver que uma entrada foi criada com uma secção e um título; não consegue ler o título a partir do registo. É deliberado: um registo que guardasse valores seria uma segunda cópia, menos protegida, dos seus conteúdos.
Ler o registo exige o âmbito de administrador. O registo é reduzido a um tamanho fixo, por isso não pode crescer sem limite.
Um limite honesto: a escrita da entrada no registo é feita na medida do possível. Se essa própria escrita falhar — por exemplo, por um erro da base de dados — a chamada não é interrompida; a falha vai para o registo do próprio Craft. Por isso, trate o registo de auditoria como um histórico muito bom, não como uma garantia de que nada pode faltar.
Ler os registos do Craft é mais restrito do que parece
A ferramenta de registos devolve as entradas de registo do Craft sem o contexto do pedido que o Craft lhes junta. Esse contexto contém $_POST, $_COOKIE e $_SESSION — incluindo, num início de sessão falhado, uma senha em texto simples. As instruções SQL e os stack traces são cortados no primeiro marcador.
É por isso que a ferramenta de registos é uma ferramenta de administrador e está desligada por predefinição.
As ferramentas de base de dados, e os seus limites
Duas ferramentas chegam à base de dados, e só uma delas executa SQL escrito por si. O craft_db_schema lista os nomes das tabelas e marca as protegidas como ilegíveis. O craft_db_query executa um SELECT sobre uma tabela e rejeita, antes de qualquer coisa chegar à base de dados:
- joins, subconsultas, common table expressions e
UNION - todas as funções exceto
count,min,max,avgesum - tabelas protegidas — utilizadores, sessões, tokens, a configuração do projeto e outras que contêm credenciais ou segredos
- expressões que indiquem a conta do servidor ou uma sequência
Uma barreira feita de regras só conhece o que lhe disseram. É por isso que ambas são ferramentas de administrador, que a ferramenta de consulta está desligada por predefinição e que nenhuma delas escreve.
Origens e DNS rebinding
Se um pedido tiver um cabeçalho Origin, este tem de estar na lista de permissões, ou o endpoint responde 403. A lista de permissões é o que configurou mais o URL do site, mas só quando este pode ser determinado estaticamente. Um URL do site construído a partir do alias @web do Craft não conta: o Craft deriva @web do cabeçalho Host do pedido recebido, por isso um atacante seria comparado com um valor escolhido por ele próprio.
Numa instalação destas, a lista configurada é a única fonte e, se estiver vazia, todos os pedidos com um Origin são recusados. Os clientes servidor-a-servidor não enviam Origin e não são afetados.
O que este plugin não faz
Cada um destes pontos é uma decisão, e cada um elimina uma classe de risco em vez de a gerir.
- Sem execução arbitrária de código. Nenhuma ferramenta executa PHP, comandos de shell ou um template que lhe seja passado.
- Sem implementação nem transferência de ficheiros. O plugin não move ficheiros e nunca toca num servidor por SSH ou FTP.
- Sem gestão do ciclo de vida de plugins. Nada instala, ativa, desativa ou remove plugins.
- Sem escrita na configuração do projeto nem nos utilizadores. O Craft impõe as regras para estes nos seus controladores; este plugin fala com a API de elementos, que não vê essas regras — por isso, não escreve lá de todo.
- Sem etiquetas. O Craft não define nenhuma permissão para etiquetas, por isso qualquer limite teria de ser inventado em vez de imposto.
- Sem valores das definições de campos. As definições de campos são devolvidas apenas como nomes, nunca como valores, porque um plugin pode pôr lá qualquer coisa. Isto não é uma promessa geral sobre segredos: a ferramenta de base de dados chega a todas as tabelas físicas cujo nome não esteja na sua lista de protegidas, e uma tabela de terceiros com um nome discreto não está nela. É exatamente por isso que essa ferramenta é para administradores e está desligada por predefinição.
Como isto se mantém verdadeiro
Cada alteração executa um conjunto de testes unitários, análise estática com PHPStan nível 6 sem baseline e uma execução de ponta a ponta numa instalação do Craft acabada de criar, em PostgreSQL 16 e MySQL 8.4. Essa execução cria um editor sem privilégios de administrador que só pode ver uma secção e trabalhar num site, e prova que o filtro de permissões corta mesmo — e não apenas que as ferramentas devolvem alguma coisa.
Encontrou algo? Comunique-o em privado para mail@cultureclub.dev, e não numa issue pública.