agentsclimarketplace

Security checks

Skill chawkitariq/fidely/.claude/skills/security-checks

PWA de fidélité pour commerces, 100% offline, sans backend, sans compte. Deux modes : Commerçant (gestion des cartes et scan client) et Client (QR code personnel).

Install
npx -y skills add chawkitariq/fidely --skill security-checks

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Checklist sécurité et RGPD avant tout commit ou ajout de feature dans Fidely. Déclencher quand : commit, ajout formulaire, manipulation IndexedDB/localStorage, scan QR, ajout dépendance, accès caméra, affichage HTML dynamique. Mots-clés : secret, API key, UUID, RGPD, données personnelles, localStorage, IndexedDB, v-html, html5-qrcode, validation input, .env, gitignore, pnpm audit.

SKILL.md

6.2 KB, as published. Nobody here has run it

Skill : Vérifications sécurité

Avant tout commit ou ajout de fonctionnalité, passer en revue ces points.

Ressources disponibles

Checklist rapide

[ ] Aucune clé API, token ou secret dans le code
[ ] Aucune donnée personnelle collectée (UUID anonymes uniquement)
[ ] localStorage/IndexedDB : utilisés correctement (client-only)
[ ] Inputs utilisateur : validés avant traitement
[ ] Dépendances tierces : versions non deprecated/vulnérables
[ ] Fichiers sensibles exclus du commit (.env, clés, etc.)

1. Données sensibles dans le code

Interdit dans tout fichier commité :

❌ const API_KEY = 'sk-abc123...'
❌ const WEBHOOK_SECRET = 'whsec_...'
❌ password: 'monmotdepasse'
❌ Authorization: 'Bearer hardcoded-token'

Ce projet n'a pas de backend actuellement — aucune clé API n'est nécessaire pour le MVP.

Si une API externe est ajoutée, les variables d'env doivent passer par nuxt.config.ts :

runtimeConfig: {
  // Côté serveur uniquement (jamais exposé au client)
  apiSecret: process.env.API_SECRET,
  public: {
    // Côté client (visible dans le bundle !)
    apiBase: process.env.NUXT_PUBLIC_API_BASE
  }
}

Et utilisées via :

const config = useRuntimeConfig()
// Serveur : config.apiSecret
// Client : config.public.apiBase

2. Données personnelles (RGPD)

Ce projet est conçu RGPD by design :

  • Les clients sont identifiés par des UUID anonymes générés localement
  • Aucun email, nom, téléphone n'est collecté ou stocké
  • Toutes les données restent dans le navigateur de l'utilisateur

Ne pas introduire de champs de formulaire demandant des données personnelles sans discussion.

Si une fonctionnalité de compte utilisateur est ajoutée, prévoir une politique de confidentialité.

3. Sécurité du stockage local

localStorage — uniquement fidely_mode (préférence UI) :

  • Donnée non sensible — préférence d'affichage uniquement
  • Ne jamais y stocker de tokens, secrets, ou données métier
  • ⚠️ Ne pas y stocker client_id — c'est dans IndexedDB

IndexedDB (fidely DB, version 2) :

Object storeContenuClé
cardsCartes de fidélité (title, reward_points, reward)id (UUID v7)
clientsPoints par client ({ cards: Record<string, number> })UUID client
configParamètres app dont client_idstring key
  • client_id est dans IndexedDB config store — stable et immuable
  • Ne jamais y stocker de données de paiement, mots de passe, ni PII

4. Validation des inputs utilisateur

Dans merchant.vue, les inputs du formulaire de carte sont validés côté client :

function validate(s: typeof state) {
  const errors = []
  if (!s.title.trim()) errors.push({ name: 'title', message: 'Champ requis' })
  if (!s.reward_points || s.reward_points < 1) errors.push({ name: 'reward_points', message: 'Minimum 1' })
  if (!s.reward.trim()) errors.push({ name: 'reward', message: 'Champ requis' })
  return errors
}

Règles à toujours respecter pour les nouveaux inputs :

  • .trim() sur tous les champs texte avant de les stocker
  • Valider les bornes numériques (min/max)
  • Sanitiser avant d'afficher dans le DOM (Vue le fait automatiquement via {{ }})
  • Ne jamais utiliser v-html avec du contenu utilisateur

Validation du QR code scanné :

// Valider le format UUID avant de naviguer
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)) {
  navigateTo(`/client/${text}`)
}

5. Dépendances tierces

Vérifier avant d'ajouter une dépendance :

pnpm audit                    # Vulnérabilités connues
pnpm outdated                 # Versions obsolètes

Dépendances à surveiller (accès caméra / DOM bas niveau) :

  • html5-qrcode 2.3.8 — accès caméra, maintenir à jour
  • qrcode 1.5.4 — génération côté client, faible risque

6. Sécurité spécifique au scan QR

Le scanner html5-qrcode lit tout QR code — un QR code malveillant pourrait contenir :

  • Une URL (ne pas ouvrir automatiquement)
  • Du texte arbitraire (ne pas l'afficher dans v-html)
  • Une fausse UUID (valider le format avant navigateTo)

Protection en place dans scan.vue :

// Seul un UUID valide déclenche la navigation
if (/^[0-9a-f]{8}-...-[0-9a-f]{12}$/i.test(trimmed)) {
  scanned.value = true // empêche le double-scan
  await navigateTo(`/client/${trimmed}`)
}

7. Fichiers à ne jamais commiter

# Déjà exclus dans .gitignore
.env
.env.*
!.env.example
.nuxt/
node_modules/
dist/

Vérifier avant git add :

git status        # Aucun .env dans les fichiers modifiés
git diff --cached # Revue du diff avant commit

8. Si des API routes SSR sont ajoutées (futur)

Si le projet évolue vers un backend Nuxt (server/api/), ajouter systématiquement :

// server/api/endpoint.post.ts
export default defineEventHandler(async (event) => {
  // 1. Lire et valider le body
  const body = await readBody(event)

  // 2. Valider avec zod ou manuellement
  if (!body.clientId || typeof body.clientId !== 'string') {
    throw createError({ statusCode: 400, message: 'clientId requis' })
  }

  // 3. Ne jamais retourner d'erreurs système raw
  try {
    // logique
  }
  catch {
    throw createError({ statusCode: 500, message: 'Erreur interne' })
  }
})

Confirmation en fin de vérification

security-checks passé

  • Secrets : [aucun secret en dur]
  • RGPD : [aucune PII collectée / stockée]
  • Stockage : [client_id dans IndexedDB, mode dans localStorage uniquement]
  • Inputs : [validation Zod + trim en place]
  • QR scan : [UUID validé par regex avant navigateTo]
  • Dépendances : [pnpm audit → 0 vulnérabilité critique]

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.