<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: luijhy michael guerra flores</title>
    <description>The latest articles on DEV Community by luijhy michael guerra flores (@luijhy_michaelguerraflo).</description>
    <link>https://dev.to/luijhy_michaelguerraflo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2461991%2F862abf92-e3ec-48e8-8ac8-317b7e09e9c2.jpg</url>
      <title>DEV Community: luijhy michael guerra flores</title>
      <link>https://dev.to/luijhy_michaelguerraflo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/luijhy_michaelguerraflo"/>
    <language>en</language>
    <item>
      <title>3 permission presets for Claude Code (strict, balanced, autonomous) and the gap none of them close</title>
      <dc:creator>luijhy michael guerra flores</dc:creator>
      <pubDate>Wed, 28 Oct 2026 19:31:26 +0000</pubDate>
      <link>https://dev.to/luijhy_michaelguerraflo/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none-of-them-close-4pn8</link>
      <guid>https://dev.to/luijhy_michaelguerraflo/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none-of-them-close-4pn8</guid>
      <description>&lt;p&gt;Every "Allow this command?" prompt in Claude Code is a small interruption. Click "always allow" enough times and you end up with a &lt;code&gt;settings.json&lt;/code&gt; nobody has read. Here are three presets I keep in &lt;code&gt;.claude/settings.json&lt;/code&gt;, from most to least careful, and the one thing none of them can do.&lt;/p&gt;

&lt;p&gt;Rules are matched in this order: &lt;strong&gt;deny&lt;/strong&gt; beats &lt;strong&gt;ask&lt;/strong&gt;, and &lt;strong&gt;ask&lt;/strong&gt; beats &lt;strong&gt;allow&lt;/strong&gt;. Anything not listed falls back to &lt;code&gt;defaultMode&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Strict: new or sensitive repos
&lt;/h2&gt;

&lt;p&gt;Read-only git is free. Commits, pushes and installs need a confirmation, and network tools are off.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"defaultMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git status)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git diff:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git log:*)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git commit:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm install:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(pnpm add:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(yarn add:*)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./secrets/**)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(curl:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(wget:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"WebFetch"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Balanced: day-to-day work
&lt;/h2&gt;

&lt;p&gt;Edits are accepted automatically (&lt;code&gt;acceptEdits&lt;/code&gt;). Lint, tests and type checks run without asking, and anything that leaves your machine or changes dependencies still asks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"defaultMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acceptEdits"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git status)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git diff:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git log:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git add:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run lint:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run test:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm test:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npx tsc --noEmit:*)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm install:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(pnpm add:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(yarn add:*)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./secrets/**)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Autonomous: throwaway branches and spikes
&lt;/h2&gt;

&lt;p&gt;All of git and npm are allowed. Use it only where a bad command costs you a branch, not a production database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"defaultMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acceptEdits"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npx:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(pnpm:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(node:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"WebFetch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"WebSearch"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./secrets/**)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The gap
&lt;/h2&gt;

&lt;p&gt;Look at the autonomous preset again: &lt;code&gt;Bash(git:*)&lt;/code&gt; allows &lt;code&gt;git push --force&lt;/code&gt; and &lt;code&gt;git reset --hard&lt;/code&gt; too. Permission rules match a command by its prefix. They can't tell a safe &lt;code&gt;git push&lt;/code&gt; from a destructive one.&lt;/p&gt;

&lt;p&gt;There's a second gap. &lt;code&gt;Read(./.env)&lt;/code&gt; blocks Claude's Read tool, but it isn't a rule about the shell. A &lt;code&gt;cat .env&lt;/code&gt; through Bash is a different tool and needs its own handling.&lt;/p&gt;

&lt;p&gt;That's what &lt;strong&gt;hooks&lt;/strong&gt; are for. A &lt;code&gt;PreToolUse&lt;/code&gt; hook is a script that sees the full command before it runs and can block it with &lt;code&gt;exit 2&lt;/code&gt;, so it can reject &lt;code&gt;git push --force&lt;/code&gt; while allowing a normal push, or refuse any command that touches &lt;code&gt;.env&lt;/code&gt;. Two free ones (one blocks destructive commands, tested against bypasses like &lt;code&gt;git push origin +main&lt;/code&gt;; one stops secrets from being written into files) are here: &lt;a href="https://github.com/kailucho/claude-code-hooks-seguridad" rel="noopener noreferrer"&gt;https://github.com/kailucho/claude-code-hooks-seguridad&lt;/a&gt; (free, MIT).&lt;/p&gt;

&lt;p&gt;Presets for convenience, hooks for safety. You want both.&lt;/p&gt;




&lt;p&gt;The three presets, the hooks, 6 skills (&lt;code&gt;/commit&lt;/code&gt;, &lt;code&gt;/pr&lt;/code&gt;, &lt;code&gt;/review&lt;/code&gt;, &lt;code&gt;/tests&lt;/code&gt;, &lt;code&gt;/plan&lt;/code&gt;, &lt;code&gt;/debug&lt;/code&gt;) and &lt;code&gt;CLAUDE.md&lt;/code&gt; templates for React, Node and GraphQL come together in the &lt;strong&gt;Starter Kit for Claude Code&lt;/strong&gt; (US$9, unofficial): &lt;a href="https://luijhy.gumroad.com/l/starter-kit-for-claude-code" rel="noopener noreferrer"&gt;https://luijhy.gumroad.com/l/starter-kit-for-claude-code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>security</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Una skill /revisar para Claude Code que encontró un bypass de auth, una inyección SQL y un secreto en logs (SKILL.md completo)</title>
      <dc:creator>luijhy michael guerra flores</dc:creator>
      <pubDate>Wed, 21 Oct 2026 18:35:06 +0000</pubDate>
      <link>https://dev.to/luijhy_michaelguerraflo/una-skill-revisar-para-claude-code-que-encontro-un-bypass-de-auth-una-inyeccion-sql-y-un-secreto-267b</link>
      <guid>https://dev.to/luijhy_michaelguerraflo/una-skill-revisar-para-claude-code-que-encontro-un-bypass-de-auth-una-inyeccion-sql-y-un-secreto-267b</guid>
      <description>&lt;p&gt;Las &lt;strong&gt;skills&lt;/strong&gt; de Claude Code son archivos Markdown que le enseñan a Claude un procedimiento repetible. Se guardan en &lt;code&gt;.claude/skills/&amp;lt;nombre&amp;gt;/SKILL.md&lt;/code&gt; y se llaman con &lt;code&gt;/&amp;lt;nombre&amp;gt;&lt;/code&gt;, o Claude las usa sola cuando tu pedido coincide con su &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esta es la skill de revisión de código que uso a diario, completa y gratis para copiar.&lt;/p&gt;

&lt;h2&gt;
  
  
  La skill
&lt;/h2&gt;

&lt;p&gt;Guárdala como &lt;code&gt;.claude/skills/revisar/SKILL.md&lt;/code&gt; en tu repo (o en &lt;code&gt;~/.claude/skills/revisar/SKILL.md&lt;/code&gt; para tenerla en todos):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;revisar&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Revisa&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;el&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;diff&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(o&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;una&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rama)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;buscando&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bugs,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;problemas&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;seguridad&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deuda,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;entrega&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hallazgos&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;priorizados.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Úsala&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cuando&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;el&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;usuario&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pida&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;revisa&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;o&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;qué&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;opinas&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;estos&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cambios&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Revisión de código&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Obtén el diff: &lt;span class="sb"&gt;`git diff`&lt;/span&gt; + &lt;span class="sb"&gt;`git diff --staged`&lt;/span&gt;, o &lt;span class="sb"&gt;`git diff &amp;lt;base&amp;gt;...HEAD`&lt;/span&gt; si el usuario nombra una rama.
&lt;span class="p"&gt;2.&lt;/span&gt; Lee el contexto necesario de cada archivo tocado (no solo las líneas del diff).
&lt;span class="p"&gt;3.&lt;/span&gt; Busca, en este orden:
&lt;span class="p"&gt;   1.&lt;/span&gt; &lt;span class="gs"&gt;**Correctitud**&lt;/span&gt;: casos borde, null/undefined, async sin &lt;span class="sb"&gt;`await`&lt;/span&gt;, condiciones de carrera, off-by-one, manejo de errores que traga excepciones.
&lt;span class="p"&gt;   2.&lt;/span&gt; &lt;span class="gs"&gt;**Seguridad**&lt;/span&gt;: inyección (SQL, comandos, XSS), secretos en código, validación de entrada, autorización faltante en resolvers/endpoints, datos sensibles en logs.
&lt;span class="p"&gt;   3.&lt;/span&gt; &lt;span class="gs"&gt;**Datos y API**&lt;/span&gt;: migraciones irreversibles, cambios incompatibles de contrato (REST/GraphQL), N+1 en resolvers.
&lt;span class="p"&gt;   4.&lt;/span&gt; &lt;span class="gs"&gt;**Rendimiento**&lt;/span&gt;: renders innecesarios en React, efectos sin dependencias correctas, consultas en bucles.
&lt;span class="p"&gt;   5.&lt;/span&gt; &lt;span class="gs"&gt;**Mantenibilidad**&lt;/span&gt;: duplicación, nombres confusos, código muerto, tests faltantes para la lógica nueva.
&lt;span class="p"&gt;4.&lt;/span&gt; Entrega una tabla ordenada por severidad:

   | Sev. | Archivo:línea | Problema | Sugerencia |
   |------|---------------|----------|------------|
   | 🔴 alta / 🟡 media / ⚪ menor | ... | ... | ... |
&lt;span class="p"&gt;
5.&lt;/span&gt; Solo reporta lo que puedas justificar con un escenario concreto. Si no encuentras nada serio, dilo. No apliques cambios salvo que el usuario lo pida.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tres detalles la hacen mejor que escribir "revisa mi código":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lee el archivo completo, no solo el diff.&lt;/strong&gt; La mayoría de bugs reales están en cómo las líneas nuevas interactúan con las que no cambiaron.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Un orden fijo.&lt;/strong&gt; Correctitud y seguridad van antes que estilo, así lo importante no queda enterrado bajo comentarios de nombres.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Solo reporta lo que puedas justificar con un escenario concreto."&lt;/strong&gt; Esa línea elimina casi todos los consejos genéricos que suelen dar las revisiones con IA.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Una prueba real
&lt;/h2&gt;

&lt;p&gt;Armé un repo de prueba con un refactor de autenticación que mete tres fallos a propósito: un bypass de auth, el secreto JWT impreso en los logs y una inyección SQL. Lo pasé por la versión en inglés de esta misma skill (mismo contenido, traducido) en Claude Code 2.1.293.&lt;/p&gt;

&lt;p&gt;Resultado: encontró los tres fallos, los puso primero como 🔴 alta, explicó para cada uno cómo se explota (por ejemplo, que &lt;code&gt;Authorization: Bearer basura&lt;/code&gt; pasaba el middleware porque &lt;code&gt;req.user = null&lt;/code&gt; seguía llamando a &lt;code&gt;next()&lt;/code&gt;) y propuso el arreglo concreto (&lt;code&gt;return res.status(401)&lt;/code&gt; antes de &lt;code&gt;next()&lt;/code&gt;, consulta parametrizada con &lt;code&gt;$1&lt;/code&gt;, borrar el &lt;code&gt;console.log&lt;/code&gt; del secreto). No tocó el código, porque la skill dice que no lo haga salvo que se lo pidas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adáptala
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Agrega a la lista del paso 3 los errores típicos de tu stack (por ejemplo, "falta &lt;code&gt;key&lt;/code&gt; en listas de React", "consultas GraphQL sin límite").&lt;/li&gt;
&lt;li&gt;Si quieres que se active sin escribir &lt;code&gt;/revisar&lt;/code&gt;, pon en la &lt;code&gt;description&lt;/code&gt; las frases que usas de verdad ("mira mis cambios", "¿algo mal aquí?").&lt;/li&gt;
&lt;li&gt;Mantén la tabla de severidad: se lee rápido y se pega tal cual en un PR.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Si te sirve, el &lt;strong&gt;Kit de Claude Code en español&lt;/strong&gt; (US$9, no oficial) trae 5 skills más en el mismo estilo (&lt;code&gt;/commit&lt;/code&gt;, &lt;code&gt;/pr&lt;/code&gt;, &lt;code&gt;/tests&lt;/code&gt;, &lt;code&gt;/plan&lt;/code&gt;, &lt;code&gt;/depurar&lt;/code&gt;), hooks de seguridad que bloquean &lt;code&gt;rm -rf&lt;/code&gt;, force-push y secretos filtrados (con 27 tests), plantillas de &lt;code&gt;CLAUDE.md&lt;/code&gt; para React, Node y GraphQL, y presets de permisos: &lt;a href="https://luijhy.gumroad.com/l/kit-claude-code-es" rel="noopener noreferrer"&gt;https://luijhy.gumroad.com/l/kit-claude-code-es&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los hooks de seguridad solos están gratis aquí: &lt;a href="https://github.com/kailucho/claude-code-hooks-seguridad" rel="noopener noreferrer"&gt;https://github.com/kailucho/claude-code-hooks-seguridad&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>spanish</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Claude Code /review skill that caught an auth bypass, SQL injection and a leaked secret (full SKILL.md)</title>
      <dc:creator>luijhy michael guerra flores</dc:creator>
      <pubDate>Wed, 14 Oct 2026 18:34:15 +0000</pubDate>
      <link>https://dev.to/luijhy_michaelguerraflo/a-claude-code-review-skill-that-caught-an-auth-bypass-sql-injection-and-a-leaked-secret-full-ham</link>
      <guid>https://dev.to/luijhy_michaelguerraflo/a-claude-code-review-skill-that-caught-an-auth-bypass-sql-injection-and-a-leaked-secret-full-ham</guid>
      <description>&lt;p&gt;Claude Code &lt;strong&gt;skills&lt;/strong&gt; are Markdown files that teach Claude a repeatable procedure. You drop one in &lt;code&gt;.claude/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt; and call it with &lt;code&gt;/&amp;lt;name&amp;gt;&lt;/code&gt;, or Claude picks it up when your request matches its &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the code review skill I use every day, complete and free to copy, plus an unedited run of it against a deliberately broken auth refactor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The skill
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;.claude/skills/review/SKILL.md&lt;/code&gt; in your repo (or in &lt;code&gt;~/.claude/skills/review/SKILL.md&lt;/code&gt; to have it everywhere):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;review&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviews&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;current&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;diff&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;branch)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bugs,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;security&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;issues&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;debt,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;returns&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;prioritized&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;findings.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;when&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;says&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;what&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;do&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;think&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;these&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;changes&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Code review&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Get the diff: &lt;span class="sb"&gt;`git diff`&lt;/span&gt; + &lt;span class="sb"&gt;`git diff --staged`&lt;/span&gt;, or &lt;span class="sb"&gt;`git diff &amp;lt;base&amp;gt;...HEAD`&lt;/span&gt; if the user names a branch.
&lt;span class="p"&gt;2.&lt;/span&gt; Read the context you need from every touched file (not just the diff lines).
&lt;span class="p"&gt;3.&lt;/span&gt; Look for, in this order:
&lt;span class="p"&gt;   1.&lt;/span&gt; &lt;span class="gs"&gt;**Correctness**&lt;/span&gt;: edge cases, null/undefined, async without &lt;span class="sb"&gt;`await`&lt;/span&gt;, race conditions, off-by-one, error handling that swallows exceptions.
&lt;span class="p"&gt;   2.&lt;/span&gt; &lt;span class="gs"&gt;**Security**&lt;/span&gt;: injection (SQL, shell, XSS), secrets in code, input validation, missing authorization in resolvers/endpoints, sensitive data in logs.
&lt;span class="p"&gt;   3.&lt;/span&gt; &lt;span class="gs"&gt;**Data and API**&lt;/span&gt;: irreversible migrations, breaking contract changes (REST/GraphQL), N+1 in resolvers.
&lt;span class="p"&gt;   4.&lt;/span&gt; &lt;span class="gs"&gt;**Performance**&lt;/span&gt;: unnecessary React renders, effects with wrong dependencies, queries in loops.
&lt;span class="p"&gt;   5.&lt;/span&gt; &lt;span class="gs"&gt;**Maintainability**&lt;/span&gt;: duplication, confusing names, dead code, missing tests for new logic.
&lt;span class="p"&gt;4.&lt;/span&gt; Return a table ordered by severity:

   | Sev. | File:line | Problem | Suggestion |
   |------|-----------|---------|------------|
   | 🔴 high / 🟡 medium / ⚪ minor | ... | ... | ... |
&lt;span class="p"&gt;
5.&lt;/span&gt; Only report what you can justify with a concrete scenario. If you find nothing serious, say so. Do not apply changes unless the user asks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details make it work better than "review my code":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It reads the whole touched file, not just the diff.&lt;/strong&gt; Most real bugs live in how the changed lines interact with the unchanged ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A fixed checklist order.&lt;/strong&gt; Correctness and security come before style, so the important findings don't get buried under naming nits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Only report what you can justify with a concrete scenario."&lt;/strong&gt; This one line removes most of the vague, generic advice LLM reviews tend to produce.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A real run
&lt;/h2&gt;

&lt;p&gt;I made a test repo with an auth refactor that introduces three bugs on purpose: an auth bypass, a secret written to the logs, and a SQL injection. Then I staged it and typed &lt;code&gt;/review&lt;/code&gt;. This is the output, unedited (Claude Code 2.1.293):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sev.&lt;/th&gt;
&lt;th&gt;File:line&lt;/th&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Suggestion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🔴 high&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/middleware/auth.ts:8-9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Auth bypass.&lt;/strong&gt; &lt;code&gt;verifyToken&lt;/code&gt; now returns &lt;code&gt;null&lt;/code&gt; for an invalid or expired token. The middleware still sets &lt;code&gt;req.user = null&lt;/code&gt; and calls &lt;code&gt;next()&lt;/code&gt;. A request with &lt;code&gt;Authorization: Bearer garbage&lt;/code&gt; therefore passes &lt;code&gt;requireAuth&lt;/code&gt;. Any handler that only checks the middleware, or reads &lt;code&gt;req.user?.sub&lt;/code&gt; loosely, is exposed.&lt;/td&gt;
&lt;td&gt;After verifying, add &lt;code&gt;if (!payload) return res.status(401).json({ error: "invalid token" });&lt;/code&gt; before &lt;code&gt;next()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔴 high&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/auth/service.ts:21&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;SQL injection.&lt;/strong&gt; &lt;code&gt;findUserByEmail&lt;/code&gt; interpolates &lt;code&gt;email&lt;/code&gt; straight into the query. An input like &lt;code&gt;' OR '1'='1&lt;/code&gt; returns arbitrary users, and &lt;code&gt;'; DROP TABLE users;--&lt;/code&gt; can run further statements, depending on the driver.&lt;/td&gt;
&lt;td&gt;Use a parameterized query, e.g. &lt;code&gt;db.query("SELECT * FROM users WHERE email = $1", [email])&lt;/code&gt;, with the placeholder syntax your driver uses. Replace &lt;code&gt;db: any&lt;/code&gt; with a real type, and select only the columns you need instead of &lt;code&gt;*&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔴 high&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/auth/service.ts:4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Secret in logs.&lt;/strong&gt; &lt;code&gt;console.log("auth init", config.JWT_SECRET)&lt;/code&gt; writes the JWT signing secret to stdout on every start. Anyone with log access can forge valid tokens.&lt;/td&gt;
&lt;td&gt;Delete the line. If you need a startup message, log without the secret.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟡 medium&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/auth/service.ts:13-17&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;catch {}&lt;/code&gt; swallows every error and returns &lt;code&gt;null&lt;/code&gt;. A bad token, an expired token and a misconfigured secret all look the same, which makes failures hard to diagnose. &lt;code&gt;jwt.verify&lt;/code&gt; can also return a string payload, so callers can't rely on &lt;code&gt;.sub&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Return a typed result, such as `{ sub: string } \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟡 medium&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;src/middleware/auth.ts:6&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;replace("Bearer ", "")&lt;/code&gt; doesn't check the scheme. A header of &lt;code&gt;Basic xyz&lt;/code&gt; becomes &lt;code&gt;Basic xyz&lt;/code&gt; and is passed to &lt;code&gt;verify&lt;/code&gt;. That is harmless once the bypass is fixed, but sloppy.&lt;/td&gt;
&lt;td&gt;Match with &lt;code&gt;/^Bearer (.+)$/&lt;/code&gt; and return 401 if it doesn't match.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚪ minor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/middleware/auth.ts:4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dropping &lt;code&gt;async&lt;/code&gt; is correct now that &lt;code&gt;verifyToken&lt;/code&gt; is synchronous.&lt;/td&gt;
&lt;td&gt;None. This is fine as is.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚪ minor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/auth/service.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;There are no tests for &lt;code&gt;verifyToken&lt;/code&gt; or &lt;code&gt;findUserByEmail&lt;/code&gt;. A test for "invalid token returns 401" would have caught the bypass.&lt;/td&gt;
&lt;td&gt;Add tests for valid, expired, malformed and missing tokens.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I recommend not merging until the three 🔴 items are fixed. I haven't changed anything. Tell me if you want me to apply the fixes.&lt;/p&gt;

&lt;p&gt;All three planted bugs were found, ranked first, and each came with a concrete exploit scenario and fix. It also didn't touch any code, because the skill says not to unless asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make it yours
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add your stack's usual suspects to step 3 (e.g. "missing &lt;code&gt;key&lt;/code&gt; in React lists", "unbounded GraphQL queries").&lt;/li&gt;
&lt;li&gt;If you want it to trigger without typing &lt;code&gt;/review&lt;/code&gt;, put the phrases you naturally use in the &lt;code&gt;description&lt;/code&gt; ("check my changes", "anything wrong here?").&lt;/li&gt;
&lt;li&gt;Keep the severity table: it makes the result scannable and easy to paste into a PR.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you want more like this, the &lt;strong&gt;Starter Kit for Claude Code&lt;/strong&gt; (US$9, unofficial) has 5 more skills in the same style (&lt;code&gt;/commit&lt;/code&gt;, &lt;code&gt;/pr&lt;/code&gt;, &lt;code&gt;/tests&lt;/code&gt;, &lt;code&gt;/plan&lt;/code&gt;, &lt;code&gt;/debug&lt;/code&gt;), safety hooks that block &lt;code&gt;rm -rf&lt;/code&gt;, force-push and leaked secrets (with 27 tests), &lt;code&gt;CLAUDE.md&lt;/code&gt; templates for React, Node and GraphQL, and permission presets: &lt;a href="https://luijhy.gumroad.com/l/starter-kit-for-claude-code" rel="noopener noreferrer"&gt;https://luijhy.gumroad.com/l/starter-kit-for-claude-code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The safety hooks alone are free here: &lt;a href="https://github.com/kailucho/claude-code-hooks-seguridad" rel="noopener noreferrer"&gt;https://github.com/kailucho/claude-code-hooks-seguridad&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>codereview</category>
      <category>productivity</category>
    </item>
    <item>
      <title>3 Claude Code hooks that prevent disasters (with code)</title>
      <dc:creator>luijhy michael guerra flores</dc:creator>
      <pubDate>Fri, 09 Oct 2026 20:55:59 +0000</pubDate>
      <link>https://dev.to/luijhy_michaelguerraflo/3-claude-code-hooks-that-prevent-disasters-with-code-178b</link>
      <guid>https://dev.to/luijhy_michaelguerraflo/3-claude-code-hooks-that-prevent-disasters-with-code-178b</guid>
      <description>&lt;p&gt;Claude Code is very good at running commands. That's exactly the problem when it runs the wrong one. &lt;strong&gt;Hooks&lt;/strong&gt; let you add a safety net that runs &lt;strong&gt;before&lt;/strong&gt; every action, without relying on the model "remembering" your rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they work (in 30 seconds)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;They're configured in &lt;code&gt;.claude/settings.json&lt;/code&gt;, per event (&lt;code&gt;PreToolUse&lt;/code&gt;, &lt;code&gt;PostToolUse&lt;/code&gt;, &lt;code&gt;Notification&lt;/code&gt;…) and per tool (&lt;code&gt;Bash&lt;/code&gt;, &lt;code&gt;Write|Edit&lt;/code&gt;…).&lt;/li&gt;
&lt;li&gt;The hook receives the event as JSON on &lt;strong&gt;stdin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If it exits with &lt;strong&gt;code 2&lt;/strong&gt;, the action is blocked and the &lt;strong&gt;stderr&lt;/strong&gt; text is sent back to Claude as the reason.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Block destructive commands
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;.claude/hooks/block-dangerous-commands.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="s1"&gt;'git[^;&amp;amp;|]*[[:space:]]push([[:space:]][^;&amp;amp;|]*)?[[:space:]](--force([^-]|$)|-[a-zA-Z]*f[a-zA-Z]*([[:space:]"]|$)|\+[^[:space:]"]+)'&lt;/span&gt;
  &lt;span class="s1"&gt;'git[^;&amp;amp;|]*[[:space:]]reset([[:space:]][^;&amp;amp;|]*)?[[:space:]]--hard'&lt;/span&gt;
  &lt;span class="s1"&gt;'DROP[[:space:]]+(TABLE|DATABASE)'&lt;/span&gt;
  &lt;span class="s1"&gt;'(curl|wget)[^|]*\|[[:space:]]*(sudo[[:space:]]+)?(ba)?sh'&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;pattern &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  if &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qiE&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Blocked: matches a dangerous pattern. Ask the user to run it."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class="nb"&gt;exit &lt;/span&gt;2
  &lt;span class="k"&gt;fi
done
&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details in the &lt;code&gt;push&lt;/code&gt; pattern: &lt;code&gt;--force([^-]|$)&lt;/code&gt; blocks &lt;code&gt;--force&lt;/code&gt; but lets &lt;code&gt;--force-with-lease&lt;/code&gt; through, which is the safe way to force-push; and &lt;code&gt;\+[^[:space:]"]+&lt;/code&gt; catches a &lt;code&gt;+&lt;/code&gt; refspec (&lt;code&gt;git push origin +main&lt;/code&gt;), which forces without ever typing &lt;code&gt;--force&lt;/code&gt;. The &lt;code&gt;git[^;&amp;amp;|]*&lt;/code&gt; prefix also catches &lt;code&gt;git -C some/dir push --force&lt;/code&gt; and &lt;code&gt;git reset -q --hard&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PreToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$CLAUDE_PROJECT_DIR&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;/.claude/hooks/block-dangerous-commands.sh"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget &lt;code&gt;chmod +x&lt;/code&gt;, then test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"tool_input":{"command":"git push origin +main"}}'&lt;/span&gt; | .claude/hooks/block-dangerous-commands.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="c"&gt;# → 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested it in a real session: I asked Claude to run &lt;code&gt;git push --force origin main&lt;/code&gt; and it came back with "blocked by a PreToolUse hook, run it yourself if you really need it".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Defense in depth:&lt;/strong&gt; a regex hook is an &lt;strong&gt;early warning&lt;/strong&gt;, not a guarantee. A reader of the Spanish version of this post found two forced-push variants that slipped past my first patterns (both fixed above). For anything irreversible, put the real block where the agent can't edit it: &lt;strong&gt;branch protection on the remote&lt;/strong&gt; with force pushes disabled. If the regex falls short, the push bounces off the server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Catch secrets before they're written
&lt;/h2&gt;

&lt;p&gt;Same pattern with &lt;code&gt;matcher: "Write|Edit|MultiEdit"&lt;/code&gt; and regexes like &lt;code&gt;AKIA[0-9A-Z]{16}&lt;/code&gt; (AWS), &lt;code&gt;sk-ant-[A-Za-z0-9_-]{20,}&lt;/code&gt; (Anthropic) or &lt;code&gt;gh[pousr]_[A-Za-z0-9]{36,}&lt;/code&gt; (GitHub). When Claude tries to write a key, it gets "use an environment variable and document it in &lt;code&gt;.env.example&lt;/code&gt;" and fixes it on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Format after every edit
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;PostToolUse&lt;/code&gt; hook that reads &lt;code&gt;file_path&lt;/code&gt; from the JSON and runs the &lt;strong&gt;project's own&lt;/strong&gt; Prettier/Biome (&lt;code&gt;node_modules/.bin/prettier&lt;/code&gt;). It always exits 0: it never blocks, it just tidies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free code
&lt;/h2&gt;

&lt;p&gt;Hooks 1 and 2, with 27 tests running on Linux and macOS, are on GitHub under MIT: &lt;a href="https://github.com/kailucho/claude-code-hooks-seguridad" rel="noopener noreferrer"&gt;https://github.com/kailucho/claude-code-hooks-seguridad&lt;/a&gt; (docs in Spanish, English summary at the top).&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want it all wired up
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Starter Kit for Claude Code&lt;/strong&gt; (US$9, unofficial) bundles the three hooks plus a notifications one, 6 skills (&lt;code&gt;/commit&lt;/code&gt;, &lt;code&gt;/pr&lt;/code&gt;, &lt;code&gt;/review&lt;/code&gt;, &lt;code&gt;/tests&lt;/code&gt;, &lt;code&gt;/plan&lt;/code&gt;, &lt;code&gt;/debug&lt;/code&gt;), &lt;code&gt;CLAUDE.md&lt;/code&gt; templates for React, Node and GraphQL, and permission presets: &lt;a href="https://luijhy.gumroad.com/l/starter-kit-for-claude-code" rel="noopener noreferrer"&gt;https://luijhy.gumroad.com/l/starter-kit-for-claude-code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What other command would you block? Let me know in the comments.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>3 hooks de Claude Code que evitan desastres (con código)</title>
      <dc:creator>luijhy michael guerra flores</dc:creator>
      <pubDate>Thu, 08 Oct 2026 04:57:47 +0000</pubDate>
      <link>https://dev.to/luijhy_michaelguerraflo/3-hooks-de-claude-code-que-evitan-desastres-con-codigo-2h3d</link>
      <guid>https://dev.to/luijhy_michaelguerraflo/3-hooks-de-claude-code-que-evitan-desastres-con-codigo-2h3d</guid>
      <description>&lt;p&gt;Claude Code es muy bueno ejecutando comandos. Ese es justo el problema cuando ejecuta el comando equivocado. Los &lt;strong&gt;hooks&lt;/strong&gt; te dejan poner una red de seguridad que corre &lt;strong&gt;antes&lt;/strong&gt; de cada acción, sin depender de que el modelo "recuerde" tus reglas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cómo funcionan (en 30 segundos)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Se configuran en &lt;code&gt;.claude/settings.json&lt;/code&gt;, por evento (&lt;code&gt;PreToolUse&lt;/code&gt;, &lt;code&gt;PostToolUse&lt;/code&gt;, &lt;code&gt;Notification&lt;/code&gt;…) y por herramienta (&lt;code&gt;Bash&lt;/code&gt;, &lt;code&gt;Write|Edit&lt;/code&gt;…).&lt;/li&gt;
&lt;li&gt;El hook recibe el evento como JSON por &lt;strong&gt;stdin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Si sale con &lt;strong&gt;código 2&lt;/strong&gt;, la acción se bloquea y el texto de &lt;strong&gt;stderr&lt;/strong&gt; se le devuelve a Claude como motivo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Bloquear comandos destructivos
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;.claude/hooks/bloquear-comandos-peligrosos.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nv"&gt;entrada&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;patrones&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="s1"&gt;'git[^;&amp;amp;|]*[[:space:]]push([[:space:]][^;&amp;amp;|]*)?[[:space:]](--force([^-]|$)|-[a-zA-Z]*f[a-zA-Z]*([[:space:]"]|$)|\+[^[:space:]"]+)'&lt;/span&gt;
  &lt;span class="s1"&gt;'git[^;&amp;amp;|]*[[:space:]]reset([[:space:]][^;&amp;amp;|]*)?[[:space:]]--hard'&lt;/span&gt;
  &lt;span class="s1"&gt;'DROP[[:space:]]+(TABLE|DATABASE)'&lt;/span&gt;
  &lt;span class="s1"&gt;'(curl|wget)[^|]*\|[[:space:]]*(sudo[[:space:]]+)?(ba)?sh'&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;patron &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;patrones&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  if &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$entrada&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qiE&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$patron&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Bloqueado: coincide con un patrón peligroso. Pide al usuario que lo ejecute."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class="nb"&gt;exit &lt;/span&gt;2
  &lt;span class="k"&gt;fi
done
&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fíjate en dos detalles del patrón de &lt;code&gt;push&lt;/code&gt;: &lt;code&gt;--force([^-]|$)&lt;/code&gt; bloquea &lt;code&gt;--force&lt;/code&gt; pero deja pasar &lt;code&gt;--force-with-lease&lt;/code&gt;, que es la forma segura; y &lt;code&gt;\+[^[:space:]"]+&lt;/code&gt; atrapa el refspec con &lt;code&gt;+&lt;/code&gt; (&lt;code&gt;git push origin +main&lt;/code&gt;), que fuerza sin escribir &lt;code&gt;--force&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PreToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$CLAUDE_PROJECT_DIR&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;/.claude/hooks/bloquear-comandos-peligrosos.sh"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No olvides &lt;code&gt;chmod +x&lt;/code&gt; y pruébalo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"tool_input":{"command":"git push origin +main"}}'&lt;/span&gt; | .claude/hooks/bloquear-comandos-peligrosos.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="c"&gt;# → 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Actualización:&lt;/strong&gt; un lector mostró en los comentarios que &lt;code&gt;git push origin +main&lt;/code&gt; y &lt;code&gt;git reset -q --hard&lt;/code&gt; pasaban la primera versión de estos patrones. Ya están corregidos (con pruebas en el repo). Y tiene razón en lo más importante: el hook es un &lt;strong&gt;aviso temprano&lt;/strong&gt;; el bloqueo de verdad es la &lt;strong&gt;protección de rama en el remoto&lt;/strong&gt; con force push desactivado. Si el regex se queda corto, el push rebota en el servidor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Detectar secretos antes de escribirlos
&lt;/h2&gt;

&lt;p&gt;Mismo patrón, pero con &lt;code&gt;matcher: "Write|Edit|MultiEdit"&lt;/code&gt; y expresiones como &lt;code&gt;AKIA[0-9A-Z]{16}&lt;/code&gt; (AWS), &lt;code&gt;sk-ant-[A-Za-z0-9_-]{20,}&lt;/code&gt; (Anthropic) o &lt;code&gt;gh[pousr]_[A-Za-z0-9]{36,}&lt;/code&gt; (GitHub). Si Claude intenta escribir una clave, recibe el mensaje "usa una variable de entorno y documéntala en &lt;code&gt;.env.example&lt;/code&gt;" y corrige solo.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Formatear después de cada edición
&lt;/h2&gt;

&lt;p&gt;Un &lt;code&gt;PostToolUse&lt;/code&gt; que lee &lt;code&gt;file_path&lt;/code&gt; del JSON y corre el Prettier/Biome &lt;strong&gt;del proyecto&lt;/strong&gt; (&lt;code&gt;node_modules/.bin/prettier&lt;/code&gt;). Siempre sale con 0: nunca bloquea, solo ordena.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código gratis
&lt;/h2&gt;

&lt;p&gt;Los hooks 1 y 2 completos, con pruebas que corren en Linux y macOS, están en GitHub con licencia MIT: &lt;a href="https://github.com/kailucho/claude-code-hooks-seguridad" rel="noopener noreferrer"&gt;https://github.com/kailucho/claude-code-hooks-seguridad&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Si quieres todo armado
&lt;/h2&gt;

&lt;p&gt;El &lt;strong&gt;Kit Claude Code en español&lt;/strong&gt; (US$9, no oficial) trae los tres hooks y uno de notificaciones, 6 skills en español (&lt;code&gt;/commit&lt;/code&gt;, &lt;code&gt;/pr&lt;/code&gt;, &lt;code&gt;/revisar&lt;/code&gt;, &lt;code&gt;/tests&lt;/code&gt;, &lt;code&gt;/plan&lt;/code&gt;, &lt;code&gt;/depurar&lt;/code&gt;), plantillas &lt;code&gt;CLAUDE.md&lt;/code&gt; para React, Node y GraphQL y presets de permisos: &lt;a href="https://luijhy.gumroad.com/l/kit-claude-code-es" rel="noopener noreferrer"&gt;https://luijhy.gumroad.com/l/kit-claude-code-es&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Qué otro comando bloquearías tú? Te leo en los comentarios.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
