SEC-P0-001B2 — Blocage IDOR IA sur les Actor Services
Statut : rapport d'implémentation Date : 2026-08-08 Périmètre traité : routes IA Actor Services uniquement
1. Objectif
SEC-P0-001B2 corrige les routes IA de génération et d'amélioration des prestations rattachées à un acteur.
La correction applique le pattern validé en SEC-P0-001B1 : validation HTTP, résolution de l'acteur ciblé, contrôle RBAC via ActorAccessService, puis seulement après autorisation accès au pipeline IA.
Aucune refonte IA globale n'est introduite.
2. Routes corrigées
Toutes les routes suivantes sont déclarées sous identify.app, auth:sanctum, throttle:ai, préfixe /api/v1/ai.
| Route | Méthode | Contrôleur | Request | actor_id | Permission ajoutée |
|---|---|---|---|---|---|
/api/v1/ai/service/generate | POST | AIController::generateServiceDescription | GenerateServiceDescriptionRequest | body nullable | manage_actor |
/api/v1/ai/service/improve | POST | AIController::improveServiceDescription | ImproveServiceDescriptionRequest | body nullable | manage_actor |
Routes volontairement exclues :
- IA publication, déjà traitée par SEC-P0-001B1 ;
- IA onboarding, réservé à un sous-chantier ultérieur ;
- lecture quota IA, réservée à un sous-chantier ultérieur ;
- durcissement backoffice et
noCreditDebit, réservé à un sous-chantier ultérieur ; - cache/quota structurels, réservés à un sous-chantier ultérieur.
3. Nature exacte des services concernés
Le terme service dans ces routes IA désigne les Actor Services, c'est-à-dire les prestations ou services rattachés à un acteur dans acteur_services.
Ces routes ne concernent pas les Municipal Services, c'est-à-dire les services municipaux gérés dans mairie_services.
Distinction validée :
| Famille | Table | Surface métier | Permission |
|---|---|---|---|
| Actor Services / prestations acteur | acteur_services | page Workspace acteur services/prestations | manage_actor |
| Municipal Services / services municipaux | mairie_services | module Mairie / Municipal Management | manage_services |
4. Divergence initiale et arbitrage
L'audit B2 a détecté une ambiguïté terminologique : la spécification B0 proposait manage_services, mais les consommateurs réels des routes /ai/service/* sont les prestations acteur.
Preuves code :
- la page Workspace des prestations acteur appelle
/ai/service/generateet/ai/service/improveavec l'actor_iddu contexte acteur ; - cette même page autorise la gestion avec
manage_actor; - les mutations backend
acteur_servicespassent parActeurPolicy::update, qui vérifiemanage_actorviaActorAccessService; - les routes
mairie_servicessont séparées et protégées parmairie.access, qui utilisemanage_services.
Arbitrage validé :
- utiliser
ActorAccessService::hasPermission(..., 'manage_actor')pour les routes IA Actor Services ; - ne pas utiliser
manage_servicessur ces routes ; - conserver
manage_servicespour les services municipaux.
5. Vulnérabilité initiale
Avant B2, les deux routes acceptaient un actor_id nullable dans le payload validé, puis le transmettaient directement à AIGatewayService.
Un utilisateur authentifié pouvait donc falsifier actor_id et déclencher, pour un acteur tiers :
- lecture ou consommation de quota IA ;
- lecture ou consommation de boost assistant ;
- lecture ou écriture cache IA ;
- appel provider ;
- écriture
ai_usage_logs.
La validation existante portait sur la forme UUID, pas sur le droit métier de l'utilisateur sur l'acteur ciblé.
6. Mécanisme RBAC
Pour tout actor_id non nul sur /ai/service/generate ou /ai/service/improve, le contrôleur appelle :
ActorAccessService::hasPermission(auth()->user(), $actorId, 'manage_actor')
Cas autorisés :
- owner de l'acteur ;
- collaborateur actif dont le rôle porte
manage_actor; - admin global, conformément au comportement historique de
ActorAccessService.
Cas refusés :
- utilisateur autorisé sur un acteur A qui fournit l'
actor_idd'un acteur B ; - collaborateur sans
manage_actor, même s'il possèdemanage_services; - collaborateur inactif ;
- utilisateur authentifié sans accès acteur ;
- relation legacy
user_acteursseule.
7. Réutilisation du pattern B1
SEC-P0-001B2 réutilise le helper local de AIController introduit par B1 en le généralisant à une permission explicite.
Le point d'application reste volontairement dans AIController, comme validé par B0 :
- le contrôleur connaît le cas d'usage HTTP et la permission cible ;
AIGatewayServicereste l'orchestrateur technique IA ;- aucune façade ou abstraction IA nouvelle n'est créée.
8. Pipeline avant / après
Avant :
HTTP
-> Form Request
-> actor_id client
-> AIGatewayService
-> quota / boost / cache / provider / logs / consommation
Après :
HTTP
-> Form Request
-> actor_id client
-> ActorAccessService::hasPermission(..., manage_actor)
-> 403 immédiat si refus
-> AIGatewayService seulement si autorisé
-> quota / boost / cache / provider / logs / consommation
9. Effets de bord bloqués
Les tests de refus B2 vérifient que le 403 intervient avant :
- appel à
AIGatewayService; - appel provider OpenAI ;
- consommation quota ;
- consommation boost ;
- écriture
ai_usage_logs; - écriture
ai_cache.
Les snapshots de tests couvrent aussi l'absence de modification de ai_user_quotas, boosts et boost_usages.
10. Tests
Tests ajoutés dans api/tests/Feature/AI/AITest.php :
- owner autorisé sur
/ai/service/generate; - collaborateur actif avec
manage_actoret sansmanage_servicesautorisé sur/ai/service/improve; - admin global autorisé ;
- régression IDOR : owner de l'acteur A avec
actor_idde l'acteur B reçoit403; - collaborateur avec
manage_servicesseulement, sansmanage_actor, reçoit403; - collaborateur inactif reçoit
403; - utilisateur sans acteur reçoit
403; - projection legacy
user_acteursseule reçoit403.
11. Compatibilité
Compatibilité conservée :
- URI inchangées ;
- méthodes HTTP inchangées ;
- payloads inchangés ;
- validation Form Request inchangée ;
- réponses des appels légitimes inchangées ;
- prompts, provider, gateway, quota, cache et logs inchangés après autorisation.
Aucune modification frontend n'a été réalisée.
12. Hors périmètre respecté
Non modifiés :
mairie_services;- permission
manage_services; - ActorPolicy ;
- RBAC global ;
- frontend Workspace ;
- onboarding IA ;
- quota IA ;
- backoffice IA ;
- cache/quota structurels.
13. Rollback
Rollback applicatif minimal :
- retirer les appels
authorizeActorForAi(..., 'manage_actor')dansgenerateServiceDescriptionetimproveServiceDescription; - conserver ou rétablir le helper B1 pour les routes publication ;
- retirer les tests B2 associés.
Le rollback réouvrirait l'IDOR sur les routes IA Actor Services.
14. Definition of Done
B2 est terminé lorsque :
- les deux routes IA Actor Services contrôlent
actor_idviaActorAccessServiceetmanage_actor; - le contrôle précède tout effet de bord IA ;
- les cas owner, collaborateur
manage_actoret admin restent autorisés ; - les cas acteur tiers, absence de permission, inactivité, absence d'accès et legacy seul retournent
403; - les tests prouvent l'absence d'effet de bord IA sur refus ;
mairie_servicesetmanage_servicesrestent inchangés ;- aucun frontend, commit ou PR n'est créé pendant la mission.