Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-34213 — Um usuário do Docmost com privilégios baixos poderia fornecer um attachmentId de vítima ao endpoint de upload genérico e sobrescrever o anexo armazenado de outra página dentro do mesmo workspace. | Kitploit
Ferramentas/GitHubGitHub/0xmrma/cve-2026-34213
Análise de VulnerabilidadesExploração de Aplicações WebTestes de PenetraçãoPapers e PesquisaAprendizado e Educação
GitHub0xmrma/cve-2026-34213

CVE-2026-34213

Um usuário do Docmost com privilégios baixos poderia fornecer um attachmentId de vítima ao endpoint de upload genérico e sobrescrever o anexo armazenado de outra página dentro do mesmo workspace.

Ver Repositório
44há 2 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2026-34213

Um usuário do Docmost com baixos privilégios poderia fornecer um attachmentId de uma vítima para o endpoint genérico de upload e sobrescrever um anexo armazenado de outra página dentro do mesmo workspace.

Introdução

Identifiquei, divulguei de forma responsável e reproduzi uma falha de autorização de Alta gravidade no Docmost, a plataforma de documentação colaborativa de código aberto.

O site oficial do Docmost apresenta a plataforma como uma wiki corporativa pronta para uso on-premise com 3M+ downloads, e afirma ser confiável por equipes de organizações como Vilnius City, Bechtle, o Governo Australiano, a Cruz Vermelha e ETS Quebec.

O bug residia no caminho genérico de upload de arquivos que o Docmost também utiliza para os fluxos de salvar/atualizar diagramas.

Eu estava revisando esse código com uma pergunta muito específica em mente:

O que acontece se o endpoint de upload comprova acesso de edição em uma página, mas o alvo da sobrescrita é selecionado com um ID de anexo separado, controlado pelo usuário?

Neste caso, essa pergunta levou diretamente a uma falha real de vinculação de objeto.

O Docmost permitia que um chamador enviasse:

  • um pageId para uma página que ele tinha permissão de editar, e
  • um attachmentId pertencente a uma página diferente no mesmo workspace
---

O servidor realizava uma verificação de consistência da sobrescrita, mas a proteção usava a lógica booleana errada.

Isso significava que a requisição poderia passar pela autorização e sobrescrever o anexo da vítima de qualquer forma.

Esse problema tornou-se CVE-2026-34213.

Docmost: docmost/docmost
Advisory: GHSA-89fp-2hch-j9gp
CVE: CVE-2026-34213
Corrigido na versão: v0.71.0

photo0

Cadeia de Ataque

pageId controlado pelo atacante com acesso de edição -> attachmentId da vítima controlado pelo atacante -> proteção de sobrescrita falha trata a sobrescrita entre páginas como válida -> caminho de armazenamento reconstruído a partir do attachmentId da vítima -> bytes do atacante substituem o arquivo da vítima -> página da vítima continua servindo o anexo modificado


O que Esta Parte do Docmost Faz

O Docmost armazena anexos de páginas enviados como registros no banco de dados, além de arquivos de suporte no armazenamento.

Para uploads normais, o servidor cria um novo ID de anexo e escreve um novo arquivo.

Para fluxos de salvar/atualizar diagramas, no entanto, o cliente intencionalmente reutiliza um attachmentId existente para que o mesmo arquivo de diagrama possa ser atualizado no lugar, em vez de gerar um novo registro de anexo a cada vez.

Esse comportamento é legítimo por si só.

O problema é que ele cria um caminho de alto risco:

  • uma entrada identifica a página que está sendo autorizada
  • outra entrada identifica o anexo que está sendo sobrescrito

Sempre que um endpoint combina essas duas responsabilidades, a implementação deve vinculá-las exatamente.

O Docmost não o fez.


Por Que Esta Superfície Valia a Pena Ser Analisada

Endpoints mistos de criação/atualização são locais comuns para bugs de autorização.

O motivo é simples:

  • fluxos de criação geralmente são autorizados contra o objeto contentor
  • fluxos de atualização geralmente são autorizados contra o registro existente
  • se um endpoint tenta fazer ambos, é fácil validar a coisa errada primeiro e tratar o segundo identificador como "apenas metadados"

Esse é exatamente o padrão aqui.

POST /api/files/upload validava que o chamador podia editar a página nomeada por pageId.

Mas se attachmentId também fosse fornecido, o servidor entrava em um caminho de sobrescrita e selecionava um registro de anexo existente separadamente.

Isso gerou a questão crítica de segurança:

o caminho de sobrescrita comprova que o anexo selecionado realmente pertence à página autorizada?

A resposta nas versões vulneráveis era não.


Causa Raiz

A causa raiz foi um desvio de autorização através de uma chave controlada pelo usuário, combinado com um bug de lógica booleana na proteção de sobrescrita.

O fluxo vulnerável era assim:

  1. AttachmentController.uploadFile() lia pageId dos dados do formulário multipart.
  2. Carregava essa página e chamava validateCanEdit(page, user).
  3. Separadamente, aceitava um attachmentId opcional da mesma requisição.
  4. AttachmentService.uploadFile() carregava o anexo existente por esse ID fornecido pelo atacante.
  5. A proteção de sobrescrita tentava verificar se o anexo existente correspondia à página autorizada.
  6. A proteção usava && em vez de rejeitar em qualquer discrepância.

A proteção vulnerável era:

root@kitploit:~
if (
  existingAttachment.pageId !== pageId &&
  existingAttachment.fileExt !== preparedFile.fileExtension &&
  existingAttachment.workspaceId !== workspaceId
) {
  throw new BadRequestException("File attachment does not match");
}

Essa condição só rejeitava a requisição se:

  • o ID da página não correspondesse, e
  • a extensão do arquivo não correspondesse, e
  • o ID do workspace não correspondesse

tudo ao mesmo tempo.

Isso é o oposto do que uma proteção de sobrescrita deveria fazer.

Para o caso real de ataque, o atacante intencionalmente permanecia dentro do mesmo workspace.

Então:

  • existingAttachment.workspaceId !== workspaceId era false

Assim que esse operando se tornava false, toda a condição && era avaliada como false, mesmo que o anexo pertencesse a uma página diferente.

Então o servidor tratava uma sobrescrita entre páginas como válida.

Essa foi a primeira metade do bug.

A segunda metade é o que tornou o impacto real.

Após a verificação, o serviço reconstruía o caminho de armazenamento de destino usando o attachmentId e o nome do arquivo fornecidos pelo atacante:

root@kitploit:~
const filePath =
  `${getAttachmentFolderPath(AttachmentType.File, workspaceId)}/` +
  `${attachmentId}/${preparedFile.fileName}`;

Em seguida, no caminho de atualização, o Docmost apenas atualizava metadados mutáveis como:

  • fileSize
  • updatedAt

Ele não reassociava a propriedade à página do atacante.

Assim, a página da vítima continuava apontando para o mesmo registro de anexo e para o mesmo ID de anexo. Apenas os bytes do arquivo subjacente mudavam.

É por isso que isso não era uma incompatibilidade inofensiva.

Era uma primitiva persistente de sobrescrita não autorizada.


Por Que Isso é um Problema de Segurança, Não Apenas um Erro de Lógica

Isso não era um bug cosmético nem um problema de colisão de nomes de arquivo.

O atacante não precisava de uma condição de corrida. O atacante não precisava adivinhar um caminho aleatório. O atacante não precisava de acesso de escrita à página da vítima.

Ele precisava apenas de:

  • acesso de leitura para aprender uma referência de anexo da vítima, e
  • acesso de escrita a qualquer outra página no mesmo workspace

A partir daí, ele podia substituir os bytes do arquivo armazenado para o anexo de outra página, enquanto a página da vítima continuava a referenciar e servir esse anexo como se nada tivesse mudado.

Isso é uma falha direta de integridade.

Em termos práticos, o atacante podia:

  • adulterar diagramas
  • substituir anexos por conteúdo enganoso
  • corromper arquivos referenciados
  • criar trilhas de auditoria confusas, porque o anexo ainda parecia pertencer à página da vítima

O ponto importante é este:

o servidor aceitou um alvo de sobrescrita escolhido pelo atacante, sem vinculá-lo à página cuja permissão de edição havia sido realmente verificada.

Isso é uma falha de controle de acesso, não apenas uma má higiene booleana.


Por Que a Exploração Era Prática

A exploração era especialmente prática para anexos de diagramas.

O cliente do Docmost intencionalmente reutiliza attachmentId para salvamentos de diagramas e usa nomes de arquivo determinísticos:

  • diagram.excalidraw.svg
  • diagram.drawio.svg

Isso é importante porque reduz os requisitos do atacante.

Para anexos genéricos, o atacante precisa de ambos:

  • o ID do anexo da vítima
  • o nome do arquivo da vítima

Para diagramas, o nome do arquivo já é previsível.

Então, se o atacante pode ler o conteúdo da página da vítima, ele frequentemente pode recuperar a única peça que falta:

  • o attachmentId da vítima

Na minha configuração de validação, usei exatamente esse caminho:

  • o atacante tinha apenas acesso de leitor ao espaço da vítima
  • o atacante tinha acesso de escritor a um espaço diferente controlado por ele
  • ambos os espaços pertenciam ao mesmo workspace

Isso foi suficiente.

O exploit atravessava limites de página e limites de espaço dentro do mesmo workspace, enquanto ainda satisfazia a verificação falha de workspace.


Prova de Conceito

Validei o problema ao vivo contra o Docmost v0.70.3 usando um laboratório descartável construído a partir de docmost/docmost:0.70.3, Postgres e Redis.

O fluxo do PoC foi:

  1. Criar uma conta de proprietário.
  2. Criar um espaço vítima e um espaço controlado pelo atacante no mesmo workspace.
  3. Convidar um segundo usuário como atacante.
  4. Conceder ao atacante:
    • acesso de leitor ao espaço vítima
    • acesso de escritor ao espaço controlado pelo atacante
  5. No espaço vítima, fazer upload de um anexo de diagrama para uma página vítima.
  6. Como atacante, recuperar as informações da página vítima e anotar o attachmentId da vítima.
  7. Enviar POST /api/files/upload com:
    • pageId = ID da página do atacante
    • attachmentId = ID do anexo da vítima
    • file = arquivo de substituição controlado pelo atacante usando o nome do arquivo da vítima
  8. Baixar o anexo da vítima antes e depois da sobrescrita e comparar hashes.

A forma mínima da requisição era:

root@kitploit:~
POST /api/files/upload
Content-Type: multipart/form-data

pageId=<attackerPageId>
attachmentId=<victimAttachmentId>
[email protected];filename=diagram.excalidraw.svg

O resultado ao vivo observado foi:

  • ID do anexo vítima aprendido pelo atacante: 019d18ae-b176-751c-8525-b5f3cede131d
  • ID da página do atacante usado para a requisição de sobrescrita: 019d18ae-b15b-70e9-ac67-64948e87cc5e
  • ID da página proprietária da vítima permaneceu: 019d18ae-b12f-75ec-8c1c-5aff3ba6be9c
  • Resposta do servidor à requisição de sobrescrita: 200 OK
  • SHA-256 do arquivo vítima antes da sobrescrita:
root@kitploit:~
686a0a0ede90ece1cbb975bb29304a6c3a90373a9c3ab2496345cf7ca59cc8fa
  • SHA-256 do arquivo vítima depois da sobrescrita:
root@kitploit:~
e0168298846cdaf75c4d880f4b721d7c0ef0ef310f75617bf2b833af34cdbeba
  • SHA-256 do payload do atacante:
root@kitploit:~
e0168298846cdaf75c4d880f4b721d7c0ef0ef310f75617bf2b833af34cdbeba
  • O armazenamento montado confirmou que o caminho da vítima agora continha:
root@kitploit:~
Substituto do atacante de outra página

Isso é uma prova completa de sobrescrita de ponta a ponta, não apenas uma revisão teórica de código-fonte.


Por Que o PoC Foi Escolhido Dessa Forma

Usei dois estilos de prova durante a triagem:

  • um harness autônomo estreito que espelhava a lógica vulnerável de sobrescrita, e
  • um exploit HTTP ao vivo completo contra uma instância descartável do Docmost

O harness autônomo foi útil para isolar a falha de lógica booleana.

O PoC HTTP ao vivo foi o artefato mais forte porque provou a história completa de segurança:

  • a autorização da página foi bem-sucedida na página do atacante
  • o attachmentId da vítima foi aceito
  • a requisição de sobrescrita retornou sucesso
  • a página da vítima permaneceu como proprietária lógica
  • os bytes armazenados no disco mudaram para conteúdo controlado pelo atacante

Essa distinção importa em bugs de controle de acesso.

"a condição está errada" não é suficiente por si só.

"a condição está errada, e a aplicação pode ser conduzida de ponta a ponta a uma sobrescrita não autorizada persistente" é o caso completo.


Análise da Correção

A correção foi lançada na v0.71.0 e mudou a proteção de sobrescrita de && para ||:

root@kitploit:~
if (
  existingAttachment.pageId !== pageId ||
  existingAttachment.fileExt !== preparedFile.fileExtension ||
  existingAttachment.workspaceId !== workspaceId
) {
  throw new BadRequestException("File attachment does not match");
}

Esse patch é mínimo, direto e correto para o bug que foi reportado.

Ele restaura a regra certa:

a sobrescrita é permitida apenas quando o anexo existente corresponde exatamente às suposições de página/workspace/tipo autorizadas.

Uma vez que a proteção rejeita qualquer incompatibilidade:

  • sobrescritas entre páginas falham
  • sobrescritas entre workspaces falham
  • incompatibilidades de tipo/extensão falham

Essa foi o tipo certo de correção:

  • sem redesenho
  • sem lógica vaga de compatibilidade
  • sem tentativa de recuperação "melhor esforço"

Apenas uma vinculação estrita entre a página autorizada e o alvo da sobrescrita.

Ainda há uma lição de engenharia mais ampla aqui:

endpoints genéricos de upload que também servem a fluxos de atualização in-loco devem ser tratados como superfícies de API de alto risco.

Mesmo quando o bug imediato é corrigido, projetos mais fortes a longo prazo são:

  • endpoints dedicados de atualização para fluxos de salvamento de diagramas
  • verificações imutáveis de vinculação no nome do arquivo, bem como no ID do anexo
  • cobertura de regressão que modele explicitamente tentativas de sobrescrita entre páginas

Mas para a vulnerabilidade em si, o patch publicado fechou o problema central de forma limpa.


Casos de Regressão que Importam

Independentemente de o projeto ter adicionado seus próprios testes privados em torno da correção, estes são os casos que importam para a cobertura de longo prazo:

  • sobrescrita com o mesmo ID de página e mesmo ID de anexo deve ser bem-sucedida
  • sobrescrita com um ID de página diferente e mesmo workspace deve falhar
  • sobrescrita com um workspace diferente deve falhar
  • sobrescrita com extensão de arquivo incompatível deve falhar
  • sobrescrita usando um nome de arquivo de diagrama conhecido, mas ID de anexo estrangeiro, deve falhar
  • sobrescrita nunca deve preservar silenciosamente a propriedade da vítima após bytes controlados pelo atacante serem escritos

O objetivo desses testes não é apenas a correção.

É travar a vinculação de autorização para que futuros "úteis" refactors de upload não reabram a mesma classe de bug.


Gravidade e Classificação

O advisory publicado classificou este problema como:

  • CWE-639: Desvio de Autorização Através de Chave Controlada pelo Usuário
  • CVSS v3.1:
root@kitploit:~
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L

Isso resulta em 7.1 / Alto, que é a conclusão correta.

A métrica importante aqui é Integridade.

Isso não era um bug de metadados de baixo nível. O atacante controlava completamente os bytes de substituição escritos no caminho do anexo de outra página, e a página da vítima continuava a servir o objeto modificado depois.

Esse é exatamente o tipo de adulteração entre registros armazenados que merece Integridade Alta.

Disponibilidade permanecendo Baixa também faz sentido, pois corromper um diagrama ou documento anexado pode tornar o conteúdo da vítima inutilizável, mas o impacto principal ainda é a modificação não autorizada, não a interrupção completa do serviço.


Divulgação

Relatei o problema de forma privada através do GitHub Security Advisories com:

  • análise de causa raiz
  • um PoC HTTP ao vivo
  • evidências de requisição/resposta
  • hashes de arquivo antes/depois
  • uma configuração de laboratório descartável fixada

O problema foi aceito pelo mantenedor, recebeu o CVE-2026-34213 e foi publicado em 14 de abril de 2026.

O advisory público lista:

  • versões afetadas: >= v0.3.0
  • versão corrigida: v0.71.0

Esse histórico também coincidiu com minha revisão local do código-fonte: a lógica vulnerável de sobrescrita estava presente na primeira versão marcada que verifiquei na linha vulnerável.


O Que Este Bug Realmente Ensina

A lição interessante aqui não é meramente "use || em vez de &&."

Isso é o sintoma.

A lição mais profunda é:

se um campo controlado pelo usuário comprova autorização e outro campo controlado pelo usuário seleciona o objeto sendo atualizado, esses dois campos devem ser vinculados explícita e exatamente.

Essa regra aparece em todos os lugares:

  • anexos de documentos
  • mídia de perfil
  • referências a objetos na nuvem
  • edições de issues/comentários
  • reprocessamento de jobs em segundo plano

No momento em que um sistema diz:

  • "você pode editar a página X"
  • "por favor, também me diga qual registro existente atualizar"

ele criou um limite de segurança que deve ser imposto com invariantes de correspondência exata.

Qualquer coisa mais suave do que isso se transforma em um bug de chave controlada pelo usuário mais cedo ou mais tarde.

Este problema também reforça um segundo ponto que é fácil de subestimar:

pequenos erros booleanos em código de proteção podem ter consequências de segurança de primeira ordem.

Uma condição de três cláusulas que "parece razoável" à primeira vista foi suficiente para inverter o modelo de proteção para o caminho de sobrescrita.

É por isso que essas superfícies merecem revisão deliberada, não confiança casual.


Pontos-Chave

  • O Docmost usava um único endpoint tanto para novos uploads quanto para atualizações in-loco de anexos.
  • A autorização era verificada contra o pageId fornecido pelo chamador, mas a seleção do alvo de sobrescrita usava um attachmentId separado fornecido pelo chamador.
  • A proteção de sobrescrita rejeitava apenas quando todas as condições de incompatibilidade eram verdadeiras ao mesmo tempo.
  • No caso de ataque no mesmo workspace, essa verificação falhava aberta.
  • O serviço reconstruía o caminho de armazenamento a partir do ID de anexo da vítima e escrevia bytes controlados pelo atacante nele.
  • O registro do anexo permanecia vinculado à página da vítima após a sobrescrita.
  • Nomes de arquivo determinísticos de diagrama tornavam a exploração especialmente prática.
  • A correção na v0.71.0 alterou corretamente a proteção para rejeitar em qualquer incompatibilidade.

Palavras Finais

Esta vulnerabilidade não era sobre comportamento exótico de armazenamento.

Era sobre um caminho de atualização que confiava em um identificador de objeto selecionado pelo atacante mais do que deveria.

O Docmost comprovou acesso de edição em uma página, aceitou um ID de anexo existente de outra página e depois deixou uma verificação de sobrescrita defeituosa transformar essa incompatibilidade em uma substituição bem-sucedida de arquivo entre páginas.

É por isso que se tornou CVE-2026-34213.

O patch na v0.71.0 corrigiu o problema imediato de forma limpa, mas a lição mais ampla permanece valiosa:

quando a autorização e a seleção de objeto são divididas em campos separados controlados pelo usuário, a vinculação exata é a propriedade de segurança.

Baixar ferramenta