Modèle de menaces & auto-attestation OWASP ASVS L1
Les menaces que Vaulted est conçu pour déjouer, celles qu'il ne déjoue pas, et une attestation contrôle par contrôle face à une référence du secteur.
Version 1.0 · Publié le 2026-04-27 · Source : main · Auteur : Maxim Novak
À propos de ce document
Il s'agit d'une auto-attestation, pas d'un audit tiers. Elle existe pour que tu puisses voir exactement ce que Vaulted prétend protéger, ce qu'il ne protège pas, et comment chaque décision de conception correspond à des contrôles reconnus. On commandera une revue indépendante et on publiera son rapport à côté de cette page dès que le budget le permettra. D'ici là, tu peux vérifier toi-même l'affirmation centrale zero-knowledge en cinq minutes avec les DevTools du navigateur.
1. Périmètre & hypothèses
Ce modèle couvre le déploiement en production de vaulted.fyi y compris son frontend web, ses routes d'API et son stockage Upstash Redis. Il couvre également le CLI et le serveur MCP publiés dans la mesure où ils interagissent avec la même API.
Hors périmètre :
- L'appareil de l'utilisateur (navigateur, OS, extensions, presse-papiers, écran).
- Le canal de communication par lequel le lien de partage est transmis (e-mail, Slack, SMS, etc.).
- Le traitement ultérieur du texte en clair par le destinataire.
- Les vulnérabilités de Vercel ou Upstash en dessous de la surface d'API que nous utilisons.
2. Actifs & frontières de confiance
Actif principal : le secret en clair. Il ne doit jamais atteindre le serveur, persister en dehors des navigateurs de l'expéditeur et du destinataire, ni être récupérable à partir du seul état côté serveur.
Actifs secondaires : le texte chiffré, les IV, les compteurs de consultations, les horodatages d'expiration, ainsi que l'intégrité et la disponibilité du service.
Frontières de confiance (par ordre de confiance décroissante) :
- Navigateur de l'expéditeur — de confiance avec le texte en clair et la clé.
- Navigateur du destinataire — de confiance avec le texte en clair et la clé après avoir saisi le lien.
- Réseau entre le client et le serveur — non fiable ; atténué par TLS 1.3 et le choix de conception selon lequel seul le texte chiffré le traverse.
- Serveur Vaulted (nous) — semi-fiable. Traité comme un stockage passif de texte chiffré. Le modèle de menaces suppose que Vaulted lui-même pourrait être compromis sans exposer le texte en clair.
- Upstash Redis — même niveau de confiance que le serveur. Uniquement des blobs chiffrés.
3. Acteurs de la menace
Observateur réseau passif. FAI, acteur sur le chemin ayant accès aux métadonnées TLS. Déjoué par TLS et par l'absence de texte en clair ou de clé sur le réseau.
Attaquant réseau actif. Peut tenter un MitM. Déjoué par TLS, le préchargement HSTS et la validation de certificat. Une compromission TLS réussie ne livre toujours que du texte chiffré.
Serveur compromis / opérateur hostile. Nous y compris. Ne peut pas lire les secrets stockés car la clé n'arrive jamais. Peut interrompre le service ou modifier le bundle JS servi — traité dans les risques résiduels ci-dessous.
Attaquant non authentifié disposant d'un lien de partage valide. Par conception, quiconque dispose du lien complet peut déchiffrer. Les limites de consultations, l'expiration et la phrase secrète optionnelle réduisent la fenêtre. C'est une propriété délibérée, pas un bug.
Attaquant ciblé contre un expéditeur ou un destinataire précis. Peut exploiter l'appareil, le canal de transmission ou le traitement du destinataire après déchiffrement. Hors du contrôle de Vaulted ; documenté par souci d'honnêteté.
4. Contrôles
- AES-256-GCM côté client avec des IV aléatoires de 96 bits issus de
crypto.getRandomValues. - Clés de 256 bits générées par secret via
crypto.subtle.generateKey; placées dans le fragment d'URL, jamais transmises. - Encapsulation optionnelle par phrase secrète avec PBKDF2 (nombre élevé d'itérations) et encapsulation de clé AES-GCM.
- Application atomique du compteur de consultations via Redis
HINCRBYavec suppression dans la même transaction à la limite. - Expiration automatique basée sur le TTL, plafonnée à 30 jours ; aucune prolongation après la création.
- Limitation de débit par IP à fenêtre glissante sur les endpoints de création et de consultation.
noindexsur les pages de consultation /s/[id] afin que les URL de secrets ne puissent pas fuiter via la recherche.- TLS 1.3 avec préchargement HSTS, en-têtes de sécurité robustes, aucune journalisation d'IP au-delà des fenêtres de limitation de débit.
5. Risques résiduels (non couverts)
Ce sont des décisions de frontière délibérées, documentées pour que les utilisateurs puissent décider si Vaulted correspond à leur modèle de menaces.
- Compromission de l'appareil. Un enregistreur de frappe, un navigateur infecté ou une extension hostile peut lire le texte en clair après déchiffrement.
- Fuite par le canal de transmission. Si le lien de partage est transféré, archivé ou cité dans une réponse à un fil d'e-mails, ce canal devient la surface d'attaque.
- Substitution ciblée du bundle. Un CDN ou un edge Vercel compromis pourrait servir un JS différent à un utilisateur précis. Subresource Integrity et les builds reproductibles sont des atténuations partielles et figurent sur la feuille de route.
- Comportement du destinataire. Une fois déchiffré, le destinataire peut copier, capturer en image ou transférer.
- Phrase secrète faible. Si elle est utilisée, une phrase secrète faible est cassable par force brute par quiconque dispose de la clé encapsulée.
- Contrainte physique / coercition. Hors périmètre de tout contrôle technique.
6. Auto-attestation OWASP ASVS L1
La matrice ci-dessous met en correspondance l'implémentation de Vaulted avec une sélection d'exigences OWASP ASVS niveau 1. Les catégories non applicables (sessions, authentification, envoi de fichiers) sont marquées N/A avec une brève justification plutôt qu'omises, pour que l'absence d'une entrée ne soit pas perçue comme une esquive.
| ID | Catégorie | Exigence | Statut | Preuve |
|---|---|---|---|---|
| V1.1.1 | Architecture | SDLC sécurisé avec modélisation des menaces pour l'application | Pass | Ce document. Révisé à chaque changement d'architecture significatif. |
| V1.4.1 | Architecture | Des points d'application de confiance appliquent les contrôles d'accès | Pass | Les gestionnaires de routes d'API valident les entrées et consomment les consultations de façon atomique via Redis HINCRBY dans src/lib/redis-secrets-store.ts. |
| V2.10.x | Authentification | Authentification de service / d'utilisateur | N/A | Vaulted est anonyme. Pas de comptes utilisateurs, pas d'authentification de service à service. L'autorisation repose sur la connaissance de l'identifiant du secret et de la clé du fragment d'URL. |
| V3.x | Gestion des sessions | Exigences de gestion des sessions | N/A | Pas de sessions, pas de cookies pour un état authentifié. |
| V5.1.3 | Validation des entrées | Validation des entrées au niveau de la couche de service de confiance | Pass | Validation manuelle à l'exécution dans src/app/api/secrets/route.ts. Charge utile ≤ 1000 caractères appliquée côté serveur ; nombre maximal de consultations et TTL bornés. |
| V5.2.5 | Assainissement | Encodage de sortie selon le contexte (HTML, JS, URL) | Pass | React échappe par défaut toutes les valeurs interpolées. Les seuls appels dangerouslySetInnerHTML rendent des littéraux JSON-LD construits côté serveur à partir de données typées. |
| V6.2.1 | Cryptographie stockée | Utiliser des algorithmes cryptographiques approuvés avec des valeurs par défaut sûres | Pass | AES-256-GCM via la Web Crypto API. NIST SP 800-38D. Voir src/lib/crypto.ts. |
| V6.2.2 | Cryptographie stockée | Génération de nombres aléatoires cryptographiquement forts | Pass | crypto.getRandomValues pour les IV et le matériel de clé. crypto.subtle.generateKey pour les clés AES. |
| V6.2.5 | Cryptographie stockée | Aucune primitive cryptographique non sécurisée ou obsolète | Pass | Aucun MD5, SHA-1, DES, RC4, ECB ou CBC-sans-MAC où que ce soit dans le chemin cryptographique. |
| V6.3.1 | Cryptographie stockée | Clés protégées contre l'accès non autorisé | Pass | La clé de chiffrement n'atteint jamais le serveur. Elle ne vit que dans le fragment d'URL, traité côté client conformément au RFC 3986. Une phrase secrète optionnelle encapsule la clé avec PBKDF2 avant le partage. |
| V7.1.1 | Gestion des erreurs & journalisation | Aucune information sensible dans les journaux | Pass | Le serveur journalise uniquement la forme de la requête et les décisions de limitation de débit. Aucun texte chiffré, aucun identifiant de secret d'une manière qui pourrait être recoupée, aucune IP persistée au-delà de la fenêtre de limitation de débit. |
| V7.4.1 | Gestion des erreurs & journalisation | Messages d'erreur génériques | Pass | Les routes d'API renvoient des codes de statut HTTP génériques et de courtes chaînes d'erreur. Aucune trace de pile ni état interne divulgué. |
| V8.1.1 | Protection des données | Données sensibles identifiées et protégées | Pass | Le texte en clair n'est jamais reçu par le serveur. Le texte chiffré est stocké chiffré au repos dans Upstash Redis avec suppression basée sur le TTL et application atomique de la limite de consultations. |
| V8.3.1 | Protection des données | Données sensibles non exposées dans les URL ou les référents | Pass | La clé de chiffrement vit dans le fragment d'URL ; les fragments ne sont jamais envoyés au serveur et sont retirés de document.referrer par les navigateurs conformément au RFC 3986 §3.5. |
| V9.1.1 | Communications | TLS pour toute la connectivité client | Pass | TLS 1.3 appliqué à l'edge Vercel. HSTS préchargé. Les requêtes HTTP sont redirigées vers HTTPS. |
| V10.3.2 | Code malveillant | Code applicatif examiné pour détecter du code malveillant | Pass | Base de code à mainteneur unique. Tous les commits sont rédigés par le propriétaire du projet ; commits signés là où c'est pris en charge. Les mises à jour de dépendances via Dependabot sont examinées avant le merge. |
| V11.1.1 | Logique métier | Flux logiques protégés contre les abus | Pass | Limitation de débit par IP via Upstash Ratelimit (10 créations/min, 30 consultations/min). Compteurs de consultations décrémentés de façon atomique. |
| V12.x | Fichiers & ressources | Exigences d'envoi et de traitement de fichiers | N/A | Vaulted n'accepte aucun envoi de fichiers. |
| V13.2.1 | API & services web | Les endpoints RESTful valident le schéma de requête | Pass | Tous les gestionnaires POST/GET valident les paramètres de chemin, la forme du corps et le content-type avant traitement. |
| V14.4.3 | Configuration | En-têtes de sécurité standard configurés | Pass | HSTS, X-Content-Type-Options, Referrer-Policy et Permissions-Policy définis via la configuration Next.js. Content-Security-Policy appliquée par requête dans src/proxy.ts avec un script-src strict-dynamic basé sur un nonce ; les routes d'API reçoivent une politique verrouillée default-src none. |
La numérotation suit la structure ASVS 4.0. La liste est sélective, pas exhaustive — l'objectif est d'être honnête sur les contrôles qui s'appliquent réellement à un stockage de texte chiffré sans état et sans compte.
7. Processus de changement
Tout changement qui affecte un élément de ce document — nouvel endpoint, changement cryptographique, refactoring touchant les dépendances, changement d'infrastructure — doit déclencher une révision de cette page dans la même PR. La version et la date de publication ci-dessus sont incrémentées lorsque le document est mis à jour ; la version précédente reste accessible dans l'historique git public.
Validation
Ce modèle de menaces est publié de bonne foi par le mainteneur de Vaulted. Les erreurs, omissions et désaccords avec les attestations ci-dessus sont explicitement les bienvenus — merci de les signaler à [email protected] ou via le programme de divulgation responsable.
Maxim Novak — mainteneur, vaulted.fyi · 2026-04-27