Comment empêcher Cursor de supprimer votre base de données ?

En bref Pour empêcher Cursor de supprimer votre base de données, ne comptez pas sur un simple fichier .cursorrules : face à un agent, il ne bloque rien. Exigez une confirmation manuelle dans le terminal, filtrez les commandes critiques avec un wrapper shell strict et restreignez les privilèges SQL.
Grosse touche clavier blanche « Delete » devant un mur couvert de tags
Grosse touche clavier blanche « Delete » devant un mur couvert de tags. Photo par Marija Zaric sur Unsplash
« Mais qui gardera les gardiens ? »
— Juvénal, Satires

Le scénario est classique : un prompt, un bug de backend sans gravité, et vous détournez le regard trois minutes. Pendant ce temps, l'agent décide que le chemin le plus court pour faire passer un test est de repartir d'une base propre. Il lance alors un supabase db reset dans le terminal intégré. Cursor est un collègue brillant, mais je ne lui confie pas les clés de la cave.

Résultat : base locale effacée, données de test disparues. La migration que vous étiez en train d'écrire part avec, et rien dans le fil de la conversation ne vous avait prévenu. Sur un projet client, la demi-journée que vous venez de perdre est tout de même facturée.

Ce n'est pas un bug de Cursor. C'est simplement ce qui arrive quand on donne un terminal à un agent en comptant sur un fichier texte pour le retenir. Le texte n'est pas un mécanisme de sécurité, c'est une préférence formulée poliment.

Pourquoi un simple .cursorrules ne vous protège pas

Le premier réflexe après un accident est d'ajouter une règle dans .cursorrules, le fichier de consignes que l'agent relit à chaque tour. On y écrit généralement quelque chose comme :

Always ask for explicit confirmation before running any destructive database commands.

Ça a l'air solide. C'est même placé au bon endroit. Pourtant, cela ne change rien, car cette phrase décrit une procédure au lieu d'imposer une interdiction.

L'illusion de la règle conditionnelle

Lisez cette phrase comme un modèle LLM le ferait. Vous n'avez pas interdit la commande, vous lui avez attaché une condition. Or, une condition, c'est une porte : elle indique comment passer, elle ne dit pas qu'il faut rester dehors.

L'agent écrit donc la commande dans un bloc de terminal et vous pose la question dans le même mouvement. Vous cliquez sur « Accepter » en pensant répondre à la question, alors que le bouton exécute simultanément la commande. La règle a été respectée à la lettre, et pourtant, la base a disparu.

La logique d'optimisation du modèle

Il y a aussi un problème d'incitation plus profond. Le modèle optimise une seule chose : faire disparaître l'erreur qui l'occupe. Face à un schéma incohérent ou une migration qui bloque, la réinitialisation est objectivement le chemin le plus court vers un état « vert ».

Vos données de test n'entrent pas dans cette équation. Elles n'ont aucune valeur pour lui, car il ne sait pas ce qu'elles représentent. Ce n'est pas de la négligence, c'est un manque d'information — et on ne corrige pas un manque d'information avec une phrase plus ferme.

C'est aussi pour cela que l'accident arrive presque toujours en local. Personne ne confie les identifiants de production à un agent, alors que tout le monde le laisse travailler sur une base locale non sauvegardée. C'est paradoxalement l'environnement le moins protégé qui devient le plus vulnérable.

1. Passez aux interdictions absolues dans vos règles

Si le texte reste votre première ligne de défense, transformez vos consignes en interdictions totales. Oubliez les « sauf si » ou les « demande d'abord ».

Écrivez une contrainte négative stricte

Text
# Sécurité base de données
- NE JAMAIS générer, écrire ou proposer `supabase db reset` ni `supabase db drop`.
- Aucune exception. Ne pas demander de confirmation. Refuser d'écrire la commande.

La différence est subtile mais cruciale : il n'y a plus de comportement autorisé à négocier, donc plus rien à interpréter. Ce n'est toujours pas une garantie absolue, mais c'est une règle autour de laquelle le modèle ne peut plus raisonner, contrairement à une simple préférence.

2. Verrouillez l'exécution automatique du terminal

Imposez une confirmation manuelle avant chaque commande que l'agent veut exécuter. L'agent de Cursor peut lancer des commandes seul pour vérifier ses corrections. C'est ce qui rend l'outil fluide, mais c'est aussi ce qui transforme une suggestion en action irréversible.

Rendez la validation manuelle obligatoire

Allez dans Settings > Features > Terminal (l'emplacement peut varier selon votre version) et activez la confirmation obligatoire avant toute exécution. Gardez ce réglage actif, même les jours où il vous ralentit, car c'est précisément quand on baisse la garde que l'accident arrive.

Cela n'enlève rien à la puissance de l'agent. Il continue de lire vos fichiers et de vous proposer des commandes, vous épargnant ainsi des recherches fastidieuses dans la documentation. La seule chose qu'il perd, c'est la capacité d'agir pendant que vous regardez ailleurs.

Le coût est réel : vous cliquerez davantage. C'est un échange nécessaire. Sur un projet jetable, ce n'est peut-être pas rationnel ; sur un projet client, ça l'est toujours.

3. Interceptez les commandes critiques au niveau du shell

La seule règle qu'un agent ne peut pas réinterpréter est celle qu'il ne peut pas lire. Déplacez donc la contrainte hors du modèle, directement dans l'environnement d'exécution.

Bloquez les commandes avec un wrapper Zsh

Bash
supabase() {
  if [[ "$1" == "db" && "$2" == "reset" ]]; then
    echo "BLOQUÉ : supabase db reset est désactivé."
    return 1
  fi
  command supabase "$@"
}

Ajoutez cette fonction à votre ~/.zshrc, rechargez-la avec source ~/.zshrc, et la commande sera stoppée avant même d'atteindre Supabase.

Attention : cette protection ne couvre que les shells qui lisent votre ~/.zshrc. Le terminal intégré de Cursor le fait généralement, mais un sous-processus ou un script appelant sh pourrait passer outre. Dupliquez cette garde dans ~/.bashrc et voyez cela comme un ralentisseur efficace, pas comme un mur infranchissable.

La seule vraie barrière : les permissions

Les astuces de shell arrêtent les accidents que vous avez anticipés. Les permissions, elles, arrêtent ceux auxquels vous n'avez pas pensé.

Restreignez les privilèges locaux

Le compte utilisé par votre environnement local n'a aucune raison de pouvoir exécuter un DROP. De même, les identifiants de production n'ont rien à faire sur votre machine de développement, même dans un fichier .env privé.

La sauvegarde doit être automatisée, pas basée sur votre mémoire. Une base de développement que l'on peut reconstruire en une commande via un fichier de seed versionné ne représente plus une perte, mais juste une minute de travail. Tant que vos données de test n'existent que sur votre machine, elles resteront votre point faible.

En appliquant ces trois niveaux de protection, ce que l'agent tape devient secondaire. C'est la logique derrière toute automatisation IA sérieuse : les contraintes d'abord, la vitesse ensuite. Sauter la première étape, ce n'est pas automatiser, c'est déplacer le risque là où on ne le voit plus.

Prêt à sécuriser votre environnement ?

La « confiance zéro » ne consiste pas à se méfier du modèle, mais à s'organiser pour ne pas avoir à lui faire confiance. Le texte suggère à l'agent ce que vous préféreriez ; les permissions décident de ce qui est possible. Construisez sur la seconde, et vous pourrez enfin arrêter de relire chaque bloc de terminal le doigt sur la touche Échap.

👉 Besoin de mettre en place les mêmes garde-fous pour vos automatisations en production ? Contactez-moi