From 2001dbfc0cf9e94949d2c68d58eef5d5fa825349 Mon Sep 17 00:00:00 2001 From: Gemini Date: Mon, 13 Jul 2026 16:34:05 -0300 Subject: [PATCH] KB-PLUGIN-044: visibilidade nativa em listagens de plugin + rights espelhados + guardas (hardening mindscrum 0.9.2) Co-Authored-By: Claude Fable 5 --- index.json | 22 ++++ ...pi11-native-visibility-in-plugin-boards.md | 104 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 records/plugin-dev/KB-PLUGIN-044-glpi11-native-visibility-in-plugin-boards.md diff --git a/index.json b/index.json index afa1010..098cba2 100755 --- a/index.json +++ b/index.json @@ -849,6 +849,28 @@ "severity": "medium", "path": "records/plugin-dev/KB-PLUGIN-043-glpi11-kanban-card-ux-patterns.md", "summary": "id: KB-PLUGIN-043" + }, + { + "id": "KB-PLUGIN-044", + "title": "\"GLPI 11 — Visibilidade nativa em listagens de plugin (tickets/projetos) e permissionamento espelhado: receita e armadilhas\"", + "domain": "plugin-dev", + "tags": [ + "glpi11", + "plugin", + "security", + "visibility", + "rights", + "profile", + "sqlprovider", + "ticket", + "project", + "hardening", + "mindscrum" + ], + "status": "active", + "severity": "critical", + "path": "records/plugin-dev/KB-PLUGIN-044-glpi11-native-visibility-in-plugin-boards.md", + "summary": "id: KB-PLUGIN-044" } ] } diff --git a/records/plugin-dev/KB-PLUGIN-044-glpi11-native-visibility-in-plugin-boards.md b/records/plugin-dev/KB-PLUGIN-044-glpi11-native-visibility-in-plugin-boards.md new file mode 100644 index 0000000..24c89cb --- /dev/null +++ b/records/plugin-dev/KB-PLUGIN-044-glpi11-native-visibility-in-plugin-boards.md @@ -0,0 +1,104 @@ +--- +id: KB-PLUGIN-044 +title: "GLPI 11 — Visibilidade nativa em listagens de plugin (tickets/projetos) e permissionamento espelhado: receita e armadilhas" +domain: plugin-dev +tags: + - glpi11 + - plugin + - security + - visibility + - rights + - profile + - sqlprovider + - ticket + - project + - hardening + - mindscrum +status: active +severity: critical +created_at: 2026-07-13 +updated_at: 2026-07-13 +applies_to: + - GLPI 11.0.8 dev + - plugin mindscrum 0.9.2 + - qualquer plugin que liste tickets/projetos fora do Search nativo +related_records: + - KB-PLUGIN-028 + - KB-PLUGIN-039 + - KB-PLUGIN-043 +--- + +# GLPI 11 — Visibilidade nativa em listagens de plugin e permissionamento espelhado + +## O problema (achado em auditoria do mindscrum) + +Um plugin que consulta `glpi_tickets`/`glpi_projects` direto com `$DB->request()` +e filtra só por `getEntitiesRestrictCriteria()` **vaza dados**: mostra a qualquer +usuário com o right do plugin TODOS os itens da entidade — ignorando as regras +nativas ("técnico vê só os seus/do grupo", "projeto visível a gerente/equipe"). +O right do plugin NÃO substitui a visibilidade por item. + +## Receita — tickets (a mesma do kanban do core) + +`CommonITILObject::getDataToDisplayOnKanban` faz (replicar): + +```php +use Glpi\Search\Provider\SQLProvider; + +$where = ['glpi_tickets.is_deleted' => 0] + getEntitiesRestrictCriteria('glpi_tickets'); +$vis = SQLProvider::getDefaultWhereCriteria(\Ticket::class); +if ($vis !== []) { + $where[] = $vis; +} +$query = ['SELECT' => [/* campos PREFIXADOS glpi_tickets.x AS x */], 'FROM' => 'glpi_tickets', 'WHERE' => $where]; + +// ⚠️ o WHERE referencia JOINs com alias hasheado (glpi_tickets_users_...): +// SEM os joins correspondentes → "Unknown column ..._users_.users_id" +$linked = []; +$join = SQLProvider::getDefaultJoinCriteria(\Ticket::class, 'glpi_tickets', $linked); +if ($join !== []) { + $query = array_merge_recursive($query, $join); +} +// joins de atores DUPLICAM linhas → deduplicar por id ($rows[$r['id']] = $r) +``` + +Armadilhas: (1) `getDefaultWhereCriteria` sem `getDefaultJoinCriteria` = SQL +quebrado; (2) campos do SELECT precisam de prefixo de tabela (joins tornam `id` +ambíguo); (3) dedup por id obrigatório. + +## Receita — projetos + +```php +$vis = \Project::getVisibilityCriteria(); // ['LEFT JOIN'=>[], 'WHERE'=>[]] +$vis['WHERE'] += getEntitiesRestrictCriteria('glpi_projects', '', '', 'auto'); +// LEFT JOIN => (seus joins) + $vis['LEFT JOIN']; WHERE => $vis['WHERE'] + (seus filtros) +// dedup por id (join com projectteams duplica) +``` + +## Permissionamento espelhado (rights do plugin por perfil) + +Conceder o right do plugin "para todos os perfis central" (mitigação C do +KB-PLUGIN-028) dá UPDATE até a Observer/Read-Only. Correto: espelhar o nativo — +`UPDATE` do plugin somente para perfis cujo right `ticket` tem `UPDATE`: + +```php +$value = READ + (($ticket_rights & UPDATE) ? UPDATE : 0); +addDefaultProfileInfos($profile_id, [RIGHT => $value], true); // drop_existing corrige base +``` +Reinstalar via console aplica a correção (install idempotente). + +## Guardas de item-alvo (defesa em profundidade) + +Right do plugin ≠ direito no item. TODA mutação deve carregar o alvo e delegar ao +nativo: `canUpdateItem()` (criar/alterar tarefa, mover, campos), `canViewItem()` +(comentar), `Ticket::canCreate()` + `canViewItem()` do projeto (spawn). Colocar as +guardas NAS CLASSES de serviço (não só no endpoint) — valem para qualquer chamador +e são testáveis em CLI. + +Teste E2E que prova: sessão com `ticket => READ` (sem READALL) deve ver só os +chamados onde é ator; sessão com rights zerados deve ter toda mutação negada. + +## Bônus — XSS de atributo em JS de plugin + +`div.textContent = s; return div.innerHTML` escapa `& < >` mas **não aspas** — +inseguro para `title="..."`/`data-x="..."`. Usar replace de `[&<>"']`.