vendeesign

security-first

"Garde-fou sécurité. Activer dès que le code touche une zone sensible : authentification/sessions, formulaires/entrées utilisateur, requêtes SQL/DB, appels API externes, gestion de secrets/clés, upload de fichiers, génération de HTML/JS dynamique, configuration CORS/CSP/headers. Prévient les failles OWASP Top 10 avant qu'elles n'arrivent en production. Complémentaire avec code-quality (qui couvre l'error handling général). Ne pas activer pour de la logique métier pure sans interaction externe (calculs, algorithmes, transformations de données internes), ni pour du code de test/mock."

vendeesign 3 1 Updated 2mo ago
GitHub

Install

npx skillscat add vendeesign/codebloom/security-first

Install via the SkillsCat registry.

SKILL.md

Security First — Prévention en amont

Ce skill s'active quand du code touche à des zones sensibles, pour prévenir les failles avant la review.

Zones de déclenchement

  • Authentification et sessions
  • Entrées utilisateur (formulaires, query params, headers)
  • Requêtes SQL ou base de données
  • Appels à des API externes
  • Gestion de secrets (clés API, tokens, mots de passe)
  • Upload et manipulation de fichiers
  • Génération de HTML/JS dynamique
  • Configuration CORS, CSP, headers de sécurité

Checklists par contexte

Authentification

  • Mots de passe hashés (bcrypt, argon2) — MD5/SHA1 sont crackables en secondes avec des rainbow tables
  • Sessions avec expiration et invalidation — une session éternelle est une porte ouverte permanente
  • Tokens JWT : secret fort, expiration courte, refresh token séparé — un JWT volé sans expiration = accès permanent
  • Rate limiting sur login/signup — sans rate limiting, le brute force est trivial
  • CORS configuré — * en production expose l'API à n'importe quel site

Entrées utilisateur

  • Tout valider côté serveur — la validation front est contournable en une ligne de DevTools
  • Sanitiser avant stockage et avant affichage — une entrée non sanitisée est un vecteur XSS ou injection
  • Utiliser les validators du framework (Zod, Joi, class-validator, etc.) — éprouvés et maintenus vs regex maison fragile
  • Limiter la taille des inputs (longueur, taille fichier) — un input de 10MB peut saturer la mémoire du serveur
// MAL — confiance aveugle
app.post('/search', (req, res) => {
  const results = search(req.body.query) // non validé, non limité
})

// BIEN — validé et limité
app.post('/search', (req, res) => {
  const { query } = schema.parse(req.body) // Zod/Joi valide et tronque
  const results = search(query)
})

Base de données

  • Requêtes paramétrées — une concaténation de string SQL = injection SQL garantie (OWASP #1)
  • ORM/query builder préféré au SQL brut — paramétrage automatique et échappement intégré
  • Moindre privilège pour les credentials DB — si l'app est compromise, les dégâts sont limités
  • Pas de données sensibles dans les logs — les logs sont souvent accessibles à plus de personnes que la DB
// MAL — injection SQL via concaténation
$wpdb->query("DELETE FROM users WHERE id = $id")

// BIEN — requête préparée
$wpdb->query($wpdb->prepare("DELETE FROM users WHERE id = %d", $id))

API externes

  • Secrets dans les variables d'environnement — un secret dans le code source finit dans l'historique git, accessible à tous les contributeurs
  • HTTPS obligatoire — HTTP en clair expose les tokens et données en transit
  • Timeout et gestion d'erreur sur chaque appel — sans timeout, un service lent peut bloquer toute l'application
  • Valider les réponses — une API tierce compromise peut injecter des données malveillantes
// MAL — pas de timeout, pas de validation
const data = await fetch(url).then(r => r.json())

// BIEN — timeout + validation de la réponse
const res = await fetch(url, { signal: AbortSignal.timeout(5000) })
if (!res.ok) throw new Error(`API error: ${res.status}`)
const data = schema.parse(await res.json())

Fichiers

  • Valider le type MIME (pas seulement l'extension)
  • Limiter la taille
  • Renommer les fichiers uploadés (pas de noms utilisateur)
  • Stocker hors du répertoire web si possible

Secrets et configuration

  • .env dans .gitignore — un .env pushé par erreur expose tous les secrets du projet, et l'historique git les garde même après suppression
  • .env.example sans valeurs réelles — sert de documentation pour l'équipe sans risque de fuite
  • Pas de clés API, tokens ou mots de passe dans le code source — git log est public sur les repos open source
  • Pas de secrets dans les logs, messages d'erreur ou réponses API — les logs sont souvent le premier endroit qu'un attaquant consulte

Patterns sûrs

Au lieu de...

// MAL — injection SQL
db.query(`SELECT * FROM users WHERE id = ${userId}`)

// BIEN — paramétré
db.query('SELECT * FROM users WHERE id = $1', [userId])
// MAL — XSS
element.innerHTML = userInput

// BIEN — échappé
element.textContent = userInput
// MAL — secret en dur
const API_KEY = "sk-abc123..."

// BIEN — variable d'environnement
const API_KEY = process.env.API_KEY

Error Handling — Aspect sécurité

  • Ne pas exposer au client : stack traces, chemins de fichiers, noms de tables, versions de framework
  • Messages d'erreur : informatifs en interne (logs), génériques vers le client
  • Pas de secrets dans les erreurs — ni dans les logs, ni dans les réponses API

Pour les bonnes pratiques générales d'error handling (catch vide, fail fast, erreurs async), voir la skill code-quality.

Comportement

  • Signaler immédiatement les failles détectées — ne pas attendre la review
  • Proposer le fix — pas juste pointer le problème
  • Ne pas sur-sécuriser — adapter au contexte (prototype vs production)
  • Traiter les erreurs mal gérées comme des failles — pas des suggestions
  • En doute sur un pattern → chercher la recommandation OWASP