Los agujeros de las apps hechas con IA casi nunca empiezan como código malo. Empiezan como una petición que suena razonable — “desactiva el RLS para que funcione” — y el agente obedece, porque obedecer es su trabajo. vibeward lo caza en cuanto lo escribes, y audita lo que ya esté desplegado. Determinista, de solo lectura, MIT.
$ npx vibeward@latest init
sin llamadas a LLM100% localsin telemetríasin cuentaes · en · pt
Tres fallos documentados en el mundo real — informes públicos de incidentes e investigación publicada, no mediciones propias de vibeward. Los tres se citan mal; lo que sigue es la versión que sobrevive a leer la fuente primaria.
Desactivar el RLS. Mover una clave service_role al cliente. Hacer público un bucket o una tabla. Quitar una comprobación de auth. Un comodín en CORS, un secreto hardcodeado, el CSRF o el rate limiting apagados, un .env a punto de commitearse. Cada una responde con el riesgo, por qué importa y la alternativa segura — “ignora las instrucciones anteriores” no funciona contra un motor de reglas.
> desactiva el RLS de la tabla users para que funcione la query ⚠ vibeward marcó una petición peligrosa ✗ Desactivar Row-Level Security por qué: apagar el RLS deja cada fila legible para cualquiera que tenga la anon key pública — la causa más común de fugas en apps hechas a prompts. haz esto en su lugar: deja el RLS activo y añade una policy: CREATE POLICY ... USING (auth.uid() = user_id)
desactiva el RLS, usa la service_role en el front, desativa o login por enquanto — las mismas reglas, sin capa de traducción y sin LLM.
No son ocho reglas escritas tres veces: los objetos peligrosos ya son independientes del idioma — RLS, service_role, CORS y .env son identificadores, no palabras. Un idioma cuesta una tabla de verbos de unas 40 entradas, que es el único tamaño que un hablante nativo puede auditar de verdad. Ese es el punto: un conjunto de reglas en un idioma que no lees es un conjunto de reglas que nadie revisa. Se agradecen PRs añadiendo una tabla.
init nunca escribe @latest en tus ajustes — es el único sitio donde sería mal negocio, porque el guardarraíl corre en cada prompt que escribes: ~1,8 s cada uno, muerto sin red, y cualquier publicación futura ejecutándose sin revisar en tu máquina. Así que busca un vibeward instalado, te ofrece instalarlo si no hay ninguno, y fija una versión exacta si prefieres que no. Los tres caminos son seguros; el binario instalado es sencillamente el más rápido.
npx vibeward@latest init --scope user
Por defecto no bloquea. UserPromptSubmit es el único hook cuyo stdout vuelve al contexto del modelo, así que el guardarraíl sale con 0 e inyecta la regla — tu prompt sobrevive y el agente corrige su propio enfoque. Un falso positivo te cuesta una nota que ignoras. --block está ahí si quieres el corte duro.
Un producto hecho con IA falla de dos formas que no tienen nada que ver: deja los datos abiertos, y deja la página vacía. Las dos merecen saberse. Reportarlas en la misma escala es cómo una fuga real acaba enterrada bajo un favicon que falta — así que vibeward las mantiene separadas, hasta el código de salida.
Contado por severidad, escrito en SARIF, y código de salida 2 ante un crítico. Ningún fichero de configuración lo silencia.
Su propia sección, su propia escala. Fuera del recuento por severidad, fuera de SARIF, fuera del código de salida. Sáltatelo entero con --no-web.
“Un favicon ausente jamás debe compartir escala con una service key expuesta.”
La service_role de Supabase y el nuevo formato sb_secret_, Stripe, OpenAI, Anthropic, Google, AWS, GitHub, Slack, Resend, Twilio, cadenas de conexión a base de datos y claves PEM privadas — en bundles o en el código, con el fichero:línea exacto.
Enumera tus tablas expuestas en vivo desde la data API y luego sondea cada una con la clave pública. Marca qué columnas contienen datos personales, revisa las filas devueltas por si traen claves de terceros, y comprueba la introspección de GraphQL.
Detecta la configuración del cliente y sondea si hay una Realtime Database abierta y un bucket de Storage listable públicamente — el patrón detrás de la brecha de Tea.
Next.js con Prisma o Drizzle: cabeceras ausentes en next.config, server actions y route handlers que mutan datos sin comprobar auth, e inyección de fórmulas en exportaciones CSV.
Inyección SQL, CORS abierto, inyección de comandos, eval y errores verbosos que filtran información en tus rutas de API.
Source maps .map desplegados, ficheros SQLite commiteados, un .env en el repo — además de CSP, HSTS y X-Frame-Options en la respuesta real.
Un robots.txt que echa a GPTBot, ClaudeBot, PerplexityBot, CCBot o Google-Extended — y un llms.txt que falta. La gente ya busca dentro de los asistentes; a un sitio que no pueden leer no lo citan.
Sin <title> — o el mismo título en todas las páginas. Sin meta description, sin canonical, sin Open Graph, sin JSON-LD, sin sitemap.xml.
Cero o varios <h1> en una página, un atributo lang ausente, imágenes desplegadas sin alt.
Sin un 404 real, sin favicon, assets rotos, errores de consola al cargar y un bundle JS sin comprimir de más de 1 MB. Los errores de consola usan Playwright si resulta que lo tienes; si no, lo dice.
Todavía en *.vercel.app o *.lovable.app, framework detectado, ver-código-fuente vacío — puntuado sobre 12. Cuánto se sigue pareciendo el sitio al día en que se generó.
vibeward detecta ausencias binarias: la etiqueta no está, el fichero nunca se escribió. Eso es lo que le falta a un sitio hecho con IA. Core Web Vitals y WCAG completo quedan fuera de alcance, a propósito.
Pregúntale a un agente “¿falta la meta description?” y se inventará una respuesta. Un parser que responde sí o no nunca lo hace. Por eso vibeward se instala en tus herramientas de IA como skill: él reporta, el agente aplica lo que puede, y luego vuelve a ejecutar vibeward para comprobarlo.
Reglas deterministas producen los hallazgos — ningún modelo de por medio, ningún hueco inventado.
Cada hallazgo trae un campo fix y otro autofix — auto, needs-input o manual — que le dicen al agente hasta dónde puede llegar solo.
vibeward vuelve a correr y lo demuestra. El mismo bucle que una suite de tests.
? ¿Dónde lo quieres? ❯ ● Este proyecto ~/Developer/mi-sitio ○ Mi cuenta ~/.claude — en todos los repos ? ¿Qué instalo? ❯ ◉ Claude Code · skill auditar + arreglar ◉ Claude Code · guard hook ◉ Cursor · regla ○ AGENTS.md · fallback fusiona ○ GitHub Action en cada push
Previsualiza cada fichero antes de tocar el disco, nunca sobrescribe uno que no escribió él, fusiona settings.json clave por clave — tus otros hooks se quedan donde están — y AGENTS.md entre marcadores. Volver a ejecutarlo es cómo se actualiza. Cualquier fichero existente se respalda en .vibeward.bak antes de su primer cambio.
Las opciones que el ámbito elegido no admite salen en gris con el motivo, no escondidas. No interactivo para CI y dotfiles:
vibeward init --scope user --all --yes
Los hallazgos de seguridad nunca se arreglan solos. Borrar una clave expuesta de un bundle no la des-filtra — solo el dueño decide cuándo se rota y si el incidente hay que comunicarlo.
Declara qué se supone que es el sitio y vibeward contrasta la realidad con eso. A una herramienta internal no se la juzga por sitemaps ni Open Graph — pero sí por assets rotos y texto alt.
{
"schemaVersion": 1,
"intent": {
"aiCrawlers": "blocked",
"siteType": "website"
},
"suppress": [
{ "id": "web_missing_og",
"reason": "private landing" }
]
}
Decir aiCrawlers: "blocked" hace que vibeward deje de llamarlo error — y plantea la pregunta mejor: ¿estás bloqueado tan a fondo como crees? Si tu robots.txt cierra la puerta a tres de los doce crawlers de IA, ese bloqueo incompleto pasa a ser el hallazgo. Creerte cerrado mientras entran nueve es peor que no haber decidido nada.
Y nunca se esconde nada. Cada supresión exige un motivo escrito, el informe imprime “producido con N supresión(es) activas” justo bajo el veredicto y las lista una a una. Solo se pueden suprimir comprobaciones de web — un veredicto del que cualquiera puede salir editando un fichero no es un veredicto.
Bundles, sondeo en vivo de Supabase y Firebase, cabeceras, source maps — y toda la pasada de web. --passive lo reduce a lo que un navegador ya se descarga, sin sondear datos en absoluto.
$ vibeward https://app.lovable.app
Un repo, o un ZIP recién salido de v0 o Bolt. Lee el código, el backend y las migraciones SQL — tablas creadas sin RLS, policies USING (true), funciones SECURITY DEFINER.
$ vibeward scan ./client-app
JSON en stdout, cada línea para humanos en stderr, así que entra directo en un parser. El payload lleva un schemaVersion — si la forma cambia, ese número cambia con ella.
$ vibeward https://app.com \
--json --stdout --yes
Los hallazgos se suben como SARIF y aterrizan en la pestaña Security del repo. El job falla ante un crítico — los hallazgos de web nunca cambian el código de salida. Apúntalo a una carpeta con path, o a una URL desplegada con url.
- uses: JSiapoDEV/[email protected]
with:
url: https://your-app.com
Suficiente para que una persona capte el riesgo en cinco segundos, y suficiente para que un agente abra un pull request correcto.
users es legible sin autenticaciónemail, phone, full_name.GET /rest/v1/users?select=* con la anon key sacada del bundle JS. Vuelven todas las filas. Sin login.autofix: manual — activa el RLS y añade una policy de propietario; no rotes nada: la anon key es pública por diseño. La exposición era la policy que faltaba.El escaneo es de solo lectura: lee tu código, tus bundles y las respuestas públicas para detectar riesgo — nunca modifica, borra ni explota. La única excepción es --write-test, explícita y opcional, que envía una sola sonda de escritura no destructiva (un insert vacío) para comprobar escrituras sin autenticar; está apagada salvo que la pidas. init es el único comando que escribe, y solo dentro de tu propio proyecto.
No. Los hallazgos de web quedan excluidos del recuento por severidad, del fichero SARIF y del código de salida — por diseño, no por configuración. Solo la seguridad bloquea. Si no los quieres ni en el informe, --no-web se salta la pasada entera.
Sí — es la comprobación estrella. Encuentra la clave pública de Supabase en tu bundle (un JWT o el nuevo formato sb_publishable_), enumera en vivo cada tabla expuesta, y marca cuáles devuelven datos sin login. Ese es exactamente el modo de fallo de Moltbook — agents, owners, agent_messages y observers legibles por cualquiera, y las tablas públicas además escribibles. Para ser precisos sobre lo que la comprobación no es: encontrar la clave sb_publishable_ en un bundle no es el hallazgo. Esa clave va en el cliente por diseño. El hallazgo es una tabla que le responde.
No. vibeward comprueba ausencias binarias — una etiqueta que no está en el HTML, un fichero que nunca se generó, un crawler al que se echó. Son las cosas que un generador se salta y a las que nadie vuelve. Core Web Vitals, presupuestos de rendimiento y una auditoría WCAG completa quedan fuera de alcance a propósito; para eso ejecuta Lighthouse.
Nunca. El escáner y el guardarraíl corren enteramente en local — sin telemetría, sin cuenta, sin subidas. La única petición saliente es a la URL a la que tú lo apuntas.
Solo las de web, y nunca en silencio. Cada entrada de vibeward.json exige un motivo escrito, y el informe indica cuántas supresiones estaban activas y qué alegaba cada una. Los hallazgos de seguridad no se pueden silenciar desde un fichero de configuración — si no, cualquiera aprobaría su propia auditoría editando un fichero.
No, y ese es el punto. Es un motor de reglas determinista, así que no se le puede convencer. "ignora las instrucciones anteriores" no funciona contra él.
Ninguno. El RLS de Supabase es una comprobación entre muchas: Firebase, claves expuestas, backends inseguros, source maps, cabeceras y toda la pasada de web funcionan en cualquier stack. Apúntalo a cualquier repo, ZIP o URL.
vibeward encuentra lo visible desde fuera y desde el código. No encuentra autorización rota a nivel de objeto detrás de un login, un límite entre inquilinos que aguanta en la primera petición y se rompe en la tercera, ni lógica de negocio que ya estaba mal antes de que nadie escribiera un prompt. No es modestia — está en el README, porque un escáner que diga lo contrario es la razón por la que la gente se fía de un tick verde del que no debería fiarse.
Eso necesita a alguien leyendo tu app, y es el trabajo que hago: reglas de Supabase y Firebase, fronteras de autenticación, y un informe escrito lo bastante concreto como para que tu propio agente actúe sobre él. Reserva 20 minutos — trae la URL.
La herramienta sigue siendo gratis y MIT pase lo que pase. No hay plan de pago ni nada reservado fuera de ella.
Sin instalar, siempre la última versión, solo lectura. Ejecútalo únicamente contra apps cuyo dueño haya autorizado la auditoría.
$ npx vibeward@latest scan ./your-app