PD-106 — Revue de sécurité (agent-adversarial)¶
Date : 2026-02-04 Scope : Code produit pour PD-106 (settingsApi, hooks, screens, components)
1. Secrets Management (INV-106-08)¶
Constat¶
- settingsApi.ts : Aucun
console.logne contient de secret (mot de passe, code TOTP, codes de récupération). Vérifié sur les fonctionsreauthenticate(),verifyTotpCode(),changePassword(). - MfaEnrollScreen.tsx : Le secret TOTP et l'URI otpauth sont stockés dans un
useStatelocal. LeuseEffectcleanup purge les données au unmount viaclearEnrollData()etclearRecoveryCodes(). - RecoveryCodesDisplay.tsx : Les codes sont reçus en props (éphémères). Aucune persistance.
- ReauthModal.tsx : Le mot de passe est dans un
useStatelocal, réinitialisé au close (useEffectsurvisible). - useReauth.ts : Le mot de passe n'est jamais stocké dans le hook — il est passé directement à l'API.
Verdict : CONFORME (INV-106-08)¶
Points de vigilance¶
- Aucun appel
SecureStore.setItemAsync()ouAsyncStorage.setItem()pour les secrets TOTP/recovery. - Aucun
console.logne contient de variable sensible. - Les tests TC-INV-01 vérifient l'absence de sentinelles dans le stockage.
2. Re-authentication (INV-106-05, INV-106-06)¶
Constat¶
- useReauth.ts :
- TTL 5 min vérifié via
Date.now() - reauthTimestampRef.current < REAUTH_TTL_MS. consume()marque la re-auth comme consommée (one-time viaconsumedRef).invalidate()réinitialise complètement l'état.- Écrans (MfaSettingsScreen, ChangePasswordScreen, DeleteAccountScreen) : Chaque écran appelle
navigation.addListener("blur", reauth.invalidate)— invalidation sur navigation hors flux. - Le mot de passe transit uniquement via
onSubmitcallback →settingsApi.reauthenticate()→ fetch. Pas de stockage intermédiaire.
Verdict : CONFORME (INV-106-05, INV-106-06)¶
Risque résiduel¶
- Le TTL client est un garde-fou UX. Le serveur fait autorité (conformément au plan section 7.3).
3. Confirmation renforcée (INV-106-14)¶
Constat¶
- DeleteAccountScreen.tsx implémente 3 barrières séquentielles :
- Saisie du mot "SUPPRIMER" (comparaison case-insensitive).
ConfirmationModalavec confirmation finale.ReauthModalpour re-authentification.- Les 3 étapes sont séquentielles et non court-circuitables.
- La comparaison utilise
toUpperCase()pour être insensible à la casse.
Verdict : CONFORME (INV-106-14)¶
4. Navigation reset après opérations destructives (INV-106-13, INV-106-15)¶
Constat¶
- SettingsScreen.tsx (logout) :
clearAllOnLogout()+CommonActions.reset()vers Login. - DeleteAccountScreen.tsx :
secureDelete()des tokens +CommonActions.reset()vers Login. - ChangePasswordScreen.tsx :
clearAllOnLogout()+CommonActions.reset()vers Login. - L'utilisation de
CommonActions.reset()dépile intégralement la navigation stack — aucun écran Settings ne reste en mémoire.
Verdict : CONFORME (INV-106-13, INV-106-15)¶
Point d'attention¶
- DeleteAccountScreen utilise
secureDelete()unitaire au lieu declearAllOnLogout(). Recommandation : utiliserclearAllOnLogout()pour garantir un nettoyage complet.
5. Erreurs non silencieuses (INV-106-16)¶
Constat¶
- Chaque opération critique (useMfa, ChangePasswordScreen, DeleteAccountScreen, SettingsScreen logout) utilise
Alert.alert()pour afficher les erreurs. - Le pattern try/catch → Alert est systématique.
- Les codes erreur API sont propagés via
result.errorsans exposition de données techniques internes.
Verdict : CONFORME (INV-106-16)¶
6. Injection / XSS¶
Constat¶
- Les traductions i18n utilisent
{{ }}interpolation (react-i18next) qui échappe par défaut. - Les données serveur (profil, codes erreur) sont rendues dans des
<Text>React Native — pas de risque XSS dans ce contexte (pas dedangerouslySetInnerHTML). - Le QR code est affiché via
<Image source={{ uri }}— pas d'exécution de script.
Verdict : CONFORME¶
7. Vulnérabilités identifiées¶
| # | Description | Sévérité | Recommandation |
|---|---|---|---|
| 1 | DeleteAccountScreen utilise secureDelete() unitaire au lieu de clearAllOnLogout() | Faible | Remplacer par clearAllOnLogout() pour cohérence |
| 2 | _handleSubmit exposé via cast as any sur useReauth — pattern fragile | Info | Refactorer pour exposer handleSubmit dans le type de retour |
| 3 | Absence de validation du format du code TOTP côté client (regex ^\d{6}$) | Info | Ajouter une validation regex avant appel API |
8. Synthèse¶
| Invariant | Statut |
|---|---|
| INV-106-05 (re-auth avant critique) | CONFORME |
| INV-106-06 (re-auth one-time) | CONFORME |
| INV-106-08 (secrets non persistés) | CONFORME |
| INV-106-09 (codes affichage unique) | CONFORME |
| INV-106-13 (logout + nettoyage) | CONFORME |
| INV-106-14 (confirmation renforcée) | CONFORME |
| INV-106-15 (post-suppression) | CONFORME avec réserve mineure |
| INV-106-16 (erreurs non silencieuses) | CONFORME |
Verdict global : CONFORME — 0 vulnérabilité critique, 3 recommandations mineures/info.