Resumo O patch para CVE- 2026 - 41894 ("Path Traversal via Double URL Encoding") saneou a rota `/export/`, mas a causa raiz **identificada permanece na rota `/ assess/*path`**. No modo de publicação (do ponto de endpoint HTTP só de leitura anônima, porta padrão 6808 ), um atacante remoto não autenticado pode ler arquivos arbitrários dentro do 'WorkspaceDir' — incluindo `conf/conf.json ' (que contém o `AccessAuthCode` SHA 256 hash, token API e chaves de sincronização), `temp/ siyuan.db`, `temp/ blocktree.db` e ` siyuan.log` — por dupla codificação de URL `..' segmentos. Verificado contra o siyuan v 3.6.5 - `GET / assets/% 252 e% 252 e/% 252 e% 252 e/conf/conf.json` → **HTTP 200, 10349 bytes (conf.json servido)** - ` GET / export/% 252 e% 252 e/% 252 e% 252 e/conf/conf.json` → HTTP 401 (patched) - ` GET / assets/% 2 e% 2 e/conf/conf.json` → HTTP 404 (decodificação única manejada corretamente).
**Passo 1 — rota & primeiro decodificar** (`kernel/ server/ serve.go: 587 - 626 `: O router registra `GET / assess/*path` para o ouvinte de publicação. Gin executa um passe de decodificação de URL em `URL.Path`, então um pedido para `/assets/% 252 e% 252 e/...` produz `context.Param("path") == "/% 2 e% 2 e/% 2 e% 2 e/conf/conf.json"` — literal `% 2 e% 2 e` strings, que `path.Clean ' não pode cair. **Passo 2 — segundo decodificação via retalho** (`kernel/ model/assets.go: 536 - 563 `, `GetAssetAbsPath`: ```go p, err:= getAssetAbsPath (relativePath) se nula!= err { // replisco descodificado, e:= url.PathUnescape(relativePath) // ← linha 548, segundo decodificar se nulo == e { p, err = getAssetAbsPath(decodificado) } } ``` Depois do retalho decodificar `% 2 e% 2 e` to `..`, `filepath.Join(DataDir, ".././conf/conf.json")` é `Limpo`-ed para `WorkspaceDir/conf/conf.json`, um arquivo existente.
**Passo 3 — portão de acesso do modo publicate- through** (`kernel/ model/publish_access.go: 288 `, `CheckAbsPathAcessívelPorPublicarAccess`): ```vai se!filelock.IsSubPath(util.DataDir, absPath) { retorna verdadeiro // ← caduca permite qualquer coisa fora do DataDir, mas dentro do WorkspaceDir } ``` Porque o arquivo resolvido é * fora* `DataDir` (é em `WorkspaceDir`), o portão retorna `verdadeiro` e `IsSensitivePath()` nunca é invocado — `.db` / `.log` / `conf/` neglists não se aplicam à rota `/assets/` em tudo (ao contrário da rota patcheada `/export/`, que verifica adicionalmente `IsSubPath(exportBaseDir,...)`). **Passo 4 — arquivo servido** (`http.ServeFile`): o pedido `URL.Path` contém literal `% 2 e% 2 e`, não `..`, então o 'Vai contém 'guarda do DotDot' passa e o arquivo é enviado.
Precondições: kernel siyuan executando com o modo de publicação ativado (`conf.publish.enable = true`). O modo Publish é o endpoint documentado de apenas leitura para compartilhar notebooks. ``` $ curl -i " 6808 /assets/% 252 e% 252 e/% 252 e% 252 e/conf/conf.json" HTTP/ 1.1 200 Lungura de conteúdo: 10349 Tipo de conteúdo: aplicativo/json... {"aparecimento": {...},"editor": {...},"sistema": {...},"acesso aoAuthCode":" ", "api": {"token":" "},...} ```.
Comparado com a rota correta: ``` $ curl -i " 6808 /export/% 252 e% 252 e/% 252 e% 252 e/conf/conf.json" HTTP/ 1.1 401 Não autorizado ``` ## Causa Raiz Três falhas independentes combinam: 1. `GetAssetAbsPath` executa um segundo `url.PathUnescape` como um retalho "compatibilidade", reintroduzindo o primitivo de duplo decodificação que o CVE- 2026 - 41894 Patch eliminado no `/ exporta/ `. 2. `CheckAbsPathAcessávelPorPublicarAccess` retorna `verdadeiro` para qualquer caminho fora de `DataDir`, mesmo quando esse caminho ainda estiver dentro de `WorkspaceDir` (que contém `conf/conf.json`, `temp/*.db`, `siyuan.log`). 3. A lista de negação de ` IsSensitivePath()` aplicada a `/ export/` não é chamada do manipulador `/ assets/`.
Impacto Arquivo remoto arbitrário não autêntico lido dentro de "WorkspaceDir". Arquivos lê-los confirmados incluem: - `conf/conf.json` — `accessAuthCode` SHA 256 (offline crackable), token API, S 3 Critérios de sincronização do /WebDAV. - `temp/siyuan.db`, `temp/blocktree.db`, `temp/ asset_content.db` — conteúdo completo do notebook (SQLite). - `siyuan.log` — caminhos internos, nome de usuário do sistema operacional, informações do plugin. Compromisso do `acessAuthCode` / token API escala para o acesso autêntico da API do kernel (leia/escreva completa de todos os notebooks). O compromisso de credenciais de sincronização aumenta para além do hospedeiro.
Consertar 1. Remova o retalho `url.PathUnescape` em `GetAssetAbsPath` (assets.go: 548 ), correspondendo ao patch `/ export/ '. 2. Em `CheckAbsPathAccessableByPublishAccess`, substitua o `IsSubPath(DataDir,...)` por uma lista de autorização explícita (apenas `DataDir` e sua subarvore publicável) e ** sempre** chame `IsSensitivePath()`. 3. Aplicar ` IsSensitivePath()` dentro do handler `/ assests/*path` no `serve.go` como defesa em profundidade. ## Estado Informado privadamente via GitHub Security Advisory. PoC reproduzida localmente contra v 3.6.5 (porta de publicação) 6808 ): ` GET / assets/% 252 e% 252 e/% 252 e% 252 e/conf/conf.json` retornou HTTP 200 / 10349 bytes.
Registro de aconselhamento: GHSA- p 4 m 3 - mgmm- c 664. Identificadores relacionados: CVE- 2026 - 54066. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 10 T 19: 25: 04.000 Z e lista a sua última modificação como 2026 - 07 - 10 T 19: 25: 04.000 Z.
Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N. Informações sobre software e versão afetadas: Go package github.com/siyuan-note/siyuan/kernel — ECOSISTEM: introduzido 0, corrigido 0.0.0 - 20260628153353 - 2 d 5 d 72223 df 4.
Classificação e evidência: identificadores de fraqueza CWE- 1188, CWE- 22, CWE- 23. O registro contém 3 suporte de referências nestes tipos: WEB, AVISO, EMBALAGAMENTO.