
Uma partilha pública parecia limpa na árvore de páginas, mas o endpoint de busca contou uma história diferente. No Docmost, páginas filhas restringidas, ocultas dos visualizadores de partilha pública, ainda podiam ser expostas através dos resultados de busca da partilha pública.
Um compartilhamento público parecia limpo na árvore de páginas, mas o endpoint de busca contava uma história diferente. No Docmost, páginas filhas restritas, ocultas dos visualizadores de compartilhamento públicos, ainda podiam vazar por meio dos resultados de busca do compartilhamento público.
Encontrei esse problema ao revisar o Docmost, uma plataforma colaborativa de wiki e documentação de código aberto, com uma pergunta muito simples em mente:
Se uma página é intencionalmente ocultada de um visualizador de compartilhamento público, todos os recursos públicos respeitam essa mesma restrição de limite?
Neste caso, a resposta foi não.
Uma página filha restrita podia permanecer oculta na árvore de compartilhamento público enquanto ainda vazava pelo endpoint de busca do compartilhamento público.
O problema foi aceito e recebeu CVE-2026-33146.
Docmost: Docmost no GitHub
CVE: CVE-2026-33146
O site oficial do Docmost o apresenta como uma wiki local pronta para empresas, com mais de 3 milhões de downloads, e afirma que é confiável por equipes em organizações como Vilnius City, Bechtle, o Governo Australiano, a Cruz Vermelha e ETS Quebec.
compartilhamento público pai com subpáginas ativadas → descendente restrito omitido da árvore pública → atacante consulta busca do compartilhamento público → título e trecho da filha restrita vazam
Docmost é uma plataforma colaborativa de wiki e documentação.
Ela oferece:
Isso significa que seu modelo de compartilhamento público é uma fronteira de segurança real.
A questão importante aqui não era se o Docmost pode compartilhar páginas publicamente.
A verdadeira questão era:
Quando o Docmost decide que uma página descendente é restrita e não deve aparecer para um visitante de compartilhamento público, essa restrição é respeitada em todos os lugares do fluxo de compartilhamento público?
Neste caso, não foi.
Muitas revisões de segurança param cedo demais ao ver uma página oculta na interface.
Isso não é suficiente.
A questão mais forte é esta:
Todo caminho de backend impõe a mesma decisão de visibilidade?
Isso importa porque os limites de segurança não são definidos pela aparência da interface.
Eles são definidos pelo que o servidor realmente retorna.
Aqui, o endpoint da árvore pública se comportou de forma segura:
Mas o caminho de busca do compartilhamento público se comportou de forma diferente:
Isso tornou essa uma questão real de autorização e divulgação de informações, não apenas uma inconsistência de apresentação.
Não abordei o Docmost testando rotas aleatoriamente na esperança de algo interessante aparecer.
O caminho mais forte foi escolher um limite de confiança primeiro.
Para aplicações que suportam:
uma das melhores perguntas a fazer é:
A camada de busca aplica exatamente o mesmo limite de autorização que a camada de navegação?
Essa pergunta se torna especialmente valiosa quando:
Foi exatamente aí que esse problema apareceu.
O bug não foi que o Docmost falhou em ocultar a página restrita na árvore pública normal.
O bug foi que a busca pública não honrava essa mesma lógica de restrição.
Da revisão do código-fonte, o fluxo da árvore pública usava travessia de descendentes com consciência de restrição.
Área relevante:
apps/server/src/core/share/share.service.tsEsse caminho intencionalmente excluía descendentes restritos usando:
getPageAndDescendantsExcludingRestricted(...)Mas o fluxo de busca do compartilhamento público seguia um caminho diferente.
Áreas relevantes:
apps/server/src/core/search/search.controller.tsapps/server/src/core/search/search.service.tsLá, o código coletava descendentes usando:
getPageAndDescendants(...)Isso significava que descendentes restritos permaneciam no escopo para a busca.
No contexto de compartilhamento público, isso importa muito porque o ramo de busca é executado sem um contexto de permissão de usuário autenticado normal. Então, uma vez que descendentes restritos eram incluídos no conjunto de páginas buscáveis, seus metadados podiam vazar através da resposta.
Porque o atacante não precisa de uma conta autenticada.
Ele precisa apenas:
Uma vez que essa condição existe, um visitante público pode consultar o endpoint de busca do compartilhamento e recuperar:
Isso é suficiente para criar um vazamento de confidencialidade, mesmo que o corpo completo da página não seja retornado.
A distinção importante é que a aplicação já sinaliza o modelo de segurança pretendido claramente.
O endpoint da árvore pública oculta descendentes restritos.
Portanto, a verdadeira pergunta não é:
“A busca por acaso retorna um conjunto de resultados mais amplo?”
A verdadeira pergunta é:
“A busca está violando uma decisão de autorização já aplicada em outro lugar para o mesmo limite de compartilhamento público?”
No Docmost, estava.
Isso transforma isso de:
em:
Por isso isso é uma vulnerabilidade real.
Validei o problema comparando os dois endpoints públicos relevantes lado a lado.
Primeiro, testei o endpoint normal da árvore pública usando a chave de compartilhamento público.
Exemplo de requisição:
POST /api/shares/tree HTTP/1.1
Host: 127.0.0.1:6752
Content-Type: application/json
{
"shareId": "public-share-key"
}
A resposta retornou apenas a página filha pública na árvore de páginas.
Resultado representativo:
{
"pageTree": [
{
"id": "public-child",
"title": "Public roadmap"
}
]
}
Isso estabeleceu o comportamento esperado do produto:
Então consultei o endpoint de busca do compartilhamento público usando um termo que aparecia dentro do descendente restrito.
Exemplo de requisição:
POST /api/search/share-search HTTP/1.1
Host: 127.0.0.1:6752
Content-Type: application/json
{
"shareId": "public-share-key",
"query": "salary"
}
A resposta incluiu a filha restrita mesmo assim:
{
"items": [
{
"id": "public-child",
"title": "Public roadmap",
"highlight": "release plan and milestones"
},
{
"id": "restricted-child",
"title": "Payroll Q4",
"highlight": "salary bands and bonus targets"
}
]
}