[{"data":1,"prerenderedAt":917},["ShallowReactive",2],{"blog-es-no-api-key-found-in-request":3,"blog-index-es":564},{"id":4,"title":5,"body":6,"category":521,"cover":522,"coverAlt":523,"description":524,"draft":525,"extension":526,"faq":527,"image":543,"keywords":544,"meta":552,"navigation":553,"ogTitle":554,"path":555,"published":556,"seo":557,"stem":558,"tldr":559,"updated":556,"__hash__":563},"blog_es\u002Fblog\u002Fno-api-key-found-in-request.md","\"No API key found in request\" en Supabase, y el arreglo equivocado",{"type":7,"value":8,"toc":508},"minimark",[9,13,24,27,35,40,43,50,53,56,62,66,69,85,102,108,118,122,127,133,143,151,155,158,161,175,192,195,200,204,207,210,277,280,283,290,297,304,309,316,320,323,332,339,345,357,376,380,383,392,400,404,410,419,435,445,462,466,495],[10,11,12],"p",{},"Ayer tu app funcionaba. Hoy una lista que solía llenarse de filas está vacía, y\nsi abres la consola del navegador hay una respuesta corta de Supabase donde\ndeberían estar los datos:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","{\n  \"message\": \"No API key found in request\",\n  \"hint\": \"No `apikey` request header or url param was found.\"\n}\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Eso es todo lo que recibes. No dice qué tabla estabas leyendo, qué enviaste ni\nqué cambiar.",[10,28,29,30,34],{},"Aquí está la parte que guía tras guía se equivoca: ",[31,32,33],"strong",{},"\"No API key found in\nrequest\" habla de una cabecera que falta, y casi todo el consejo que encontrarás\nhabla de las reglas de tu base de datos."," En el foro de discusión de Supabase\neste mensaje tiene un hilo propio, dieciséis personas proponen allí ocho remedios\ndistintos, y tres de ellos dicen que añadas o aflojes una regla en alguna de tus\ntablas. Todos los que lo probaron cuentan que el mensaje paró. Si una regla fue\nalguna vez la causa es otra pregunta, y el hilo nunca la resuelve. Lo único\nseguro después es que más gente puede leer la tabla que antes.",[36,37,39],"h2",{"id":38},"qué-significa-no-api-key-found-in-request","Qué significa \"No API key found in request\"",[10,41,42],{},"Supabase rechazó tu petición en la puerta de la calle, antes de preguntarle nada\na tu base de datos.",[10,44,45,46,49],{},"Cada petición a tu proyecto llega primero a una puerta de entrada que Supabase\ncoloca delante de todo lo demás. Su trabajo en ese momento es estrecho: leer la\ncabecera ",[21,47,48],{},"apikey",", comparar el valor con las claves que tiene tu proyecto y pasar\nla petición. Si no hay clave que leer se detiene ahí y responde 401, el código de\nestado para \"no sé quién eres\". La propia referencia de la puerta de entrada de\nSupabase dice que una clave ausente o inválida se rechaza así.",[10,51,52],{},"Piensa en ella como un portero en la puerta de la calle y no como una cerradura\nen un archivador. El portero pide un pase a todo el que llega. Las reglas que\ndeciden quién puede abrir cada archivador están dos pisos más arriba, y aquí\nnadie las consultó, porque nada pasó de la entrada.",[10,54,55],{},"Así que, como errores, este es suave. No se leyó nada, no se escribió nada y tus\ndatos están exactamente como estaban. Una petición fue rechazada.",[57,58],"diagram",{"alt":59,"caption":60,"src":61},"Una ruta de izquierda a derecha, de una app a una puerta alta. La puerta lleva una ranura discontinua vacía y una barra ámbar, la flecha se detiene ahí, y una línea discontinua corta al otro lado no lleva a ninguna parte. Más a la derecha hay un candado y una tabla en gris, dentro de un marco discontinuo.","La puerta de entrada lee la clave. Las reglas de tu tabla están una parada más adentro, y una petición rechazada nunca llega a ellas.","\u002Fblog\u002Fno-api-key-found-in-request\u002Fwhere-it-stops-1600x620.png",[36,63,65],{"id":64},"por-qué-llegó-mi-petición-sin-clave","¿Por qué llegó mi petición sin clave?",[10,67,68],{},"Porque el valor que tu app debía enviar no estaba en la petición que tu navegador\nhizo de verdad. Cuatro causas cubren casi todos los casos.",[10,70,71,74,75,78,79,84],{},[31,72,73],{},"La clave nunca llegó a la app compilada."," Tu código la lee de una variable de\nentorno, la compilación que produjo tu sitio en vivo no tenía esa variable, y\n",[21,76,77],{},"createClient"," recibió una cadena vacía. Todo compila, la app carga y cada\npetición sale sin clave. En un proyecto Vite o Next la variable además tiene que\nllevar el prefijo que la marca como segura para el navegador, que es\n",[80,81,83],"a",{"href":82},"\u002Fblog\u002Fvite-and-next-public-env-vars","una trampa en sí misma",".",[10,86,87,90,91,94,95,98,99,101],{},[31,88,89],{},"Estás llamando a la ruta REST a mano."," Un ",[21,92,93],{},"fetch"," escrito contra\n",[21,96,97],{},"\u002Frest\u002Fv1\u002Ftu_tabla"," envía las cabeceras que escribiste y nada más. La librería\ncliente de Supabase añade ",[21,100,48],{}," por ti; una petición escrita a mano lleva lo\nque tú le diste.",[10,103,104,107],{},[31,105,106],{},"Algo en medio la descartó."," Una regla de reescritura, un proxy o una puerta de\nenlace propia se sienta entre tu app y Supabase y reenvía la petición sin la\ncabecera.",[10,109,110,113,114,117],{},[31,111,112],{},"Estás mirando una redirección y no una petición de datos."," Si el mensaje\naparece después de que alguien inicie sesión o pulse un enlace de confirmación, y\nla barra de direcciones aún muestra tu URL de Supabase, el ajuste que toca mirar\nes la Site URL dentro de Auth. La respuesta con más reacciones de todo ese hilo\nde Supabase es de alguien que había escrito allí la dirección de su sitio sin el\n",[21,115,116],{},"https:\u002F\u002F"," delante.",[36,119,121],{"id":120},"el-arreglo-en-una-línea","El arreglo, en una línea",[10,123,124,125,84],{},"Envía tu clave publicable en la cabecera ",[21,126,48],{},[14,128,131],{"className":129,"code":130,"language":19},[17],"import { createClient } from '@supabase\u002Fsupabase-js'\n\nexport const supabase = createClient(\n  'https:\u002F\u002Ftu-proyecto.supabase.co',\n  'sb_publishable_…',\n)\n",[21,132,130],{"__ignoreMap":23},[10,134,135,136,138,139,142],{},"Si creas el cliente así, la librería pone la clave en la cabecera correcta en\ncada petición que hace, y tú nunca escribes la cabecera. La referencia de\nSupabase es concreta sobre cuál es: las claves publicables y secretas viajan en\n",[21,137,48],{}," y no en ",[21,140,141],{},"Authorization: Bearer",", porque son cadenas opacas y cortas y\ntodo lo que intenta verificarlas como un JWT falla.",[10,144,145,146,150],{},"Esa clave tiene que estar en tu app. Dice a qué proyecto pertenece una petición,\ny lo que un visitante con ella alcanza lo deciden las reglas de tus tablas, que\nes la razón entera de que pueda ser pública.\n",[80,147,149],{"href":148},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Qué claves de API son seguras en tu frontend","\nrecorre el resto de la familia.",[36,152,154],{"id":153},"el-arreglo-que-lo-empeora","El arreglo que lo empeora",[10,156,157],{},"La clave secreta entra en la misma cabecera, y en un proyecto antiguo calla el\nmensaje y sigue funcionando.",[10,159,160],{},"Eso es un solo clic mal dado. Tu panel lista ambas claves en la misma página, y\nel par antiguo se parece: misma forma, misma longitud, una debajo de la otra. Lo\ngrave que sea el clic depende de qué par emite tu proyecto.",[10,162,163,166,167,170,171,174],{},[31,164,165],{},"Una clave secreta nueva se rechaza en el navegador."," Supabase bloquea\n",[21,168,169],{},"sb_secret_…"," mirando la cabecera ",[21,172,173],{},"User-Agent"," y responde 401. Pegar una en tu\nfrontend no quita el error, que es el mejor resultado disponible aquí.",[10,176,177,184,185,187,188,191],{},[31,178,179,180,183],{},"Una clave ",[21,181,182],{},"service_role"," antigua no tiene ese bloqueo."," Funciona. La lista se\nllena, la app se comporta igual que la semana pasada, y la clave queda en un\narchivo que cualquier visitante puede descargar. Allí ignora todas las reglas que\nhas escrito: ",[21,186,182],{}," lleva el atributo ",[21,189,190],{},"BYPASSRLS"," de Postgres, así que\nuna política nunca se le aplica. Cada fila de cada tabla, legible y escribible\npor quien abra el archivo.",[10,193,194],{},"La nota de Supabase sobre el bloqueo del navegador merece leerse dos veces. El\nbloqueo responde 401, y un atacante todavía puede usar la clave con otras\nherramientas. Lo que protege son las peticiones de tu propia app; la misma clave\nen el mismo archivo responde a una petición enviada desde un script.",[57,196],{"alt":197,"caption":198,"src":199},"Una clave dibujada dos veces. Arriba, su ruta desde una ventana de navegador se detiene en una barra ámbar sólida con el número 401. Abajo, la misma clave sale de una terminal y atraviesa el lugar donde estaría esa barra, dibujada aquí como un contorno discontinuo, hasta tres filas de tabla rellenas en rojo.","El bloqueo del navegador es sobre el navegador. La misma clave en el mismo archivo funciona desde cualquier cosa que no lo sea.","\u002Fblog\u002Fno-api-key-found-in-request\u002Fthe-browser-block-1600x640.png",[36,201,203],{"id":202},"el-otro-camino-equivocado-y-por-qué-es-tan-fácil","El otro camino equivocado, y por qué es tan fácil",[10,205,206],{},"Aflojar una regla en la tabla también calla el mensaje, y cambia quién puede leer\ntus filas.",[10,208,209],{},"Aquí está ese hilo de Supabase entero, agrupado por lo que cada respuesta te pide\ncambiar:",[211,212,213,229],"table",{},[214,215,216],"thead",{},[217,218,219,223,226],"tr",{},[220,221,222],"th",{},"Qué cambiar",[220,224,225],{},"Cuántas de las ocho respuestas",[220,227,228],{},"Qué cambia eso de verdad",[230,231,232,244,255,265],"tbody",{},[217,233,234,238,241],{},[235,236,237],"td",{},"La Site URL dentro de Auth",[235,239,240],{},"1",[235,242,243],{},"Dónde aterriza una redirección",[217,245,246,249,252],{},[235,247,248],{},"Una política o un grant",[235,250,251],{},"3",[235,253,254],{},"Quién lee y escribe tus filas",[217,256,257,260,262],{},[235,258,259],{},"La consulta o la sesión",[235,261,251],{},[235,263,264],{},"Tu propio código",[217,266,267,272,274],{},[235,268,269,270],{},"La cabecera ",[21,271,48],{},[235,273,240],{},[235,275,276],{},"Lo que la puerta estaba pidiendo",[10,278,279],{},"La última fila es la que responde a la pista del mensaje. Es el comentario de más\nabajo del hilo y tiene un solo voto.",[10,281,282],{},"Ninguna de las otras siete está escrita de mala fe, y eso es lo que lo hace\ndifícil. Un mensaje aparece de verdad en varias situaciones, quien responde hizo\nfuncionar de verdad su propia app, y una política que ya faltaba es algo real que\narreglar. Lo que sale mal es el orden: se reescribe una regla para callar un\nmensaje sobre una cabecera, y la regla es la parte de ese par que nadie revisa\ndespués. Tu app funciona en ambos casos, así que nada te dice cuál de los dos\nhiciste.",[10,284,285,286,289],{},"Desde fuera, el resultado se ve. Nuestro escáner lee apps en vivo como lo haría\nun desconocido, y de las 31.056 apps que ha calificado, ",[31,287,288],{},"tres"," publicaron una\nclave secreta de Supabase. Eso lo convierte en el hallazgo más raro que tenemos y\nel más grave.",[10,291,292,293,296],{},"El impulso de al lado es mucho más común. Detrás de 8.435 de esas apps\nencontramos un proyecto de Supabase. En 3.680 de ellas la pregunta \"¿puede un\ndesconocido leer esta tabla?\" llegó a tener una respuesta útil, y ",[31,294,295],{},"2.096\nrespondieron que sí",": al menos una tabla entregó filas a una petición de fuera\nsin ninguna cuenta de por medio. En 394 de ellas la tabla abierta estaba nombrada\ncomo una tabla de personas.",[10,298,299,300,84],{},"Parte de eso es deliberado. Un menú publicado, una página de anuncios y un\nchangelog público viven todos en tablas que un desconocido debe leer, y nuestro\nescáner no puede distinguirlas de una tabla de clientes que se abrió por\ndescuido. Informa de lo que respondió y te deja el juicio a ti, que es la razón\nde que\n",[80,301,303],{"href":302},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","activar Row Level Security no sea lo mismo que estar protegido",[57,305],{"alt":306,"caption":307,"src":308},"Tres barras en una misma escala, estrechándose hacia abajo. La primera son todas las apps donde se encontró un proyecto de Supabase. La segunda es el número menor en el que la pregunta sobre la tabla obtuvo respuesta, con el resto continuando como un contorno discontinuo con un signo de interrogación. La tercera son las apps que respondieron que sí.","Lo que un desconocido puede leer, sobre las apps que respondieron. La banda discontinua son las apps que no respondieron nada, que no es lo mismo que una app sin nada abierto.","\u002Fblog\u002Fno-api-key-found-in-request\u002Fwhat-answered-1600x620.png",[10,310,311,312,84],{},"Si prefieres ver tu propia respuesta antes que deducirla, nuestro escaneo\ngratuito lee tu sitio en vivo y te dice qué alcanza desde fuera. Tarda unos 20\nsegundos y no necesita cuenta: ",[80,313,315],{"href":314},"\u002Fsecurity-scanner","escanea tu app",[36,317,319],{"id":318},"cómo-saber-qué-clave-pegaste","Cómo saber qué clave pegaste",[10,321,322],{},"Lee el principio de la cadena.",[10,324,325,328,329,331],{},[21,326,327],{},"sb_publishable_…"," pertenece a tu app. ",[21,330,169],{}," nunca. No hay nada que\ndescodificar, porque para qué sirve la clave está escrito en su frente.",[10,333,334,335,338],{},"Un valor largo que empieza por ",[21,336,337],{},"eyJ"," es una del par antiguo, y ahí es donde las\ndos se vuelven difíciles de distinguir. La sección central de una clave así es\ninformación legible y no cifrado, y lleva un campo que resuelve la pregunta:",[14,340,343],{"className":341,"code":342,"language":19},[17],"{\n  \"iss\": \"supabase\",\n  \"role\": \"anon\",          ← el que importa\n  \"iat\": 1750000000\n}\n",[21,344,342],{"__ignoreMap":23},[10,346,347,350,351,353,354,356],{},[21,348,349],{},"anon"," es la publicable del par. ",[21,352,182],{}," es la que toca rotar hoy. La\ndocumentación de Supabase lo dice más seco de lo que lo diríamos nosotros: si un\ntutorial o un asistente de IA te dice que copies una clave larga que empieza por\n",[21,355,337],{},", se escribió para las claves antiguas.",[10,358,359,360,362,363,365,366,370,371,375],{},"Los dos pares pueden estar activos a la vez, y ese es el detalle con el que la\ngente tropieza. Crear una clave publicable o secreta deja tus claves ",[21,361,349],{}," y\n",[21,364,182],{}," exactamente donde estaban, y siguen funcionando hasta que las\ndesactivas en el panel como un paso aparte.\n",[80,367,369],{"href":368},"\u002Fblog\u002Fsupabase-new-api-keys","Qué cambió con las claves nuevas"," cubre esa\nmigración, y\n",[80,372,374],{"href":373},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","dónde vive cada valor en tu panel"," es la\npágina que abrir si nunca has estado allí.",[36,377,379],{"id":378},"si-la-clave-secreta-ya-está-en-tu-app","Si la clave secreta ya está en tu app",[10,381,382],{},"Rótala antes de tocar nada más, y trabaja en el orden que da Supabase.",[10,384,385,386,388,389,391],{},"Crea una clave secreta nueva en el panel. Sustituye la vieja en todos los sitios\ndonde tu proyecto la usa. Comprueba que cada parte de tu app está en la nueva.\nSolo entonces retira la vieja, y el último paso cambia según el par que tengas:\nborrar una clave secreta no se puede deshacer, mientras que desactivar un par\n",[21,387,349],{}," y ",[21,390,182],{}," antiguo es reversible, así que puedes volver a\nactivarlas si se te escapó algún cliente.",[10,393,394,395,399],{},"Si rotas primero o reparas la fuga primero depende de si ya hay una copia\npública.\n",[80,396,398],{"href":397},"\u002Fblog\u002Frotate-supabase-service-role-key","Rotar una clave service_role de Supabase","\nrecorre los dos órdenes y qué leer en tus registros después.",[36,401,403],{"id":402},"que-siga-así-cuando-el-error-ya-no-aparece","Que siga así cuando el error ya no aparece",[10,405,406,409],{},[31,407,408],{},"El arreglo aguanta hasta el siguiente prompt o cambio que toque tu\nconfiguración de Supabase."," Basta un prompt para volver a meter una clave o\naflojar otra vez una regla, y tu app sigue funcionando en los dos casos, así que\nsolo se nota cuando alguien mira.",[10,411,412],{},[31,413,414,418],{},[80,415,417],{"href":416},"\u002Fpricing","Reeve Monitor"," mira por ti:",[420,421,422,426,429,432],"ul",{},[423,424,425],"li",{},"las nueve comprobaciones cada hora, en hasta tres apps",[423,427,428],{},"un correo el día en que un nuevo escaneo le pone a tu app una nota más baja que el anterior",[423,430,431],{},"si la app responde, cada 60 segundos",[423,433,434],{},"un informe mensual de lo que vio",[10,436,437],{},[31,438,439,440,444],{},"Una clave que puede escribir cada fila también puede vaciar cada tabla.\n",[80,441,443],{"href":442},"\u002Fsupabase-backups","Reeve Care"," guarda una copia de tu base de Supabase donde\nninguna clave de tu app puede llegar.",[420,446,447,450,453,456,459],{},[423,448,449],{},"una copia cifrada cada día, guardada fuera de tu cuenta de Supabase",[423,451,452],{},"cada copia verificada antes de contar, con un recuento de las filas de cada tabla",[423,454,455],{},"una restauración con un clic que guarda lo que hay ahora antes de reemplazar nada",[423,457,458],{},"también tus archivos subidos, en cuanto conectes una credencial de Storage",[423,460,461],{},"todo lo que hace Monitor",[36,463,465],{"id":464},"qué-hacer-hoy","Qué hacer hoy",[467,468,469],"key-takeaways",{},[420,470,471,474,480,489,492],{},[423,472,473],{},"Lee el mensaje como un rechazo en la puerta. Tus filas no se tocaron y no hay nada que recuperar.",[423,475,476,477,479],{},"Mira en la pestaña de red del navegador la petición que falla y comprueba si hay siquiera una cabecera ",[21,478,48],{},". Esa única mirada te dice si es un problema de clave o de redirección.",[423,481,482,483,485,486,488],{},"Crea tu cliente de Supabase con la clave publicable y deja que la librería envíe la cabecera. ",[21,484,327],{}," en un proyecto nuevo, la clave ",[21,487,349],{}," en uno antiguo.",[423,490,491],{},"Si ya hay una clave secreta en tu app, rótala primero. Borrarla del código no cierra la puerta, porque la versión antigua sigue en tu historial y en cualquier copia en caché de tu sitio.",[423,493,494],{},"Devuelve a su sitio cualquier regla que aflojaras persiguiendo esto, y luego compruébala desde fuera y no desde la vista previa de tu builder.",[10,496,497,498,502,503,507],{},"Empieza por la única tabla de la que vino el error, y lee después las políticas de\ncada tabla que tocaste esa misma semana. La\n",[80,499,501],{"href":500},"\u002Fchecklist","checklist de seguridad de 10 minutos"," cubre qué más suele quedarse\nabierto en una app recién lanzada, y la\n",[80,504,506],{"href":505},"\u002Fis-your-supabase-app-safe","guía de seguridad de Supabase"," recorre el resto de lo\nque un desconocido puede alcanzar.",{"title":23,"searchDepth":509,"depth":509,"links":510},3,[511,513,514,515,516,517,518,519,520],{"id":38,"depth":512,"text":39},2,{"id":64,"depth":512,"text":65},{"id":120,"depth":512,"text":121},{"id":153,"depth":512,"text":154},{"id":202,"depth":512,"text":203},{"id":318,"depth":512,"text":319},{"id":378,"depth":512,"text":379},{"id":402,"depth":512,"text":403},{"id":464,"depth":512,"text":465},"Fundamentos de seguridad","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcover-1200x630.png","Una petición llega a una puerta alta con la ranura del pase vacía y una barra cruzada, y la base de datos a la que iba se queda intacta detrás.","\"No API key found in request\" significa que tu petición llegó a Supabase sin clave. Casi todas las respuestas apuntan a las reglas de tu base de datos.",false,"md",[528,531,534,537,540],{"q":529,"a":530},"¿Qué significa \"No API key found in request\"?","Significa que tu petición llegó a Supabase sin la cabecera apikey, así que la puerta de entrada que Supabase pone delante de tu proyecto la rechazó antes de que tu base de datos interviniera. No se leyó nada, no se escribió nada y nada cambió en tus datos. La respuesta trae una pista que dice lo mismo con otras palabras: no apikey request header or url param was found.",{"q":532,"a":533},"¿Qué clave de Supabase va en la cabecera apikey?","Tu clave publicable, que es sb_publishable_ en un proyecto nuevo y la clave anon en uno más antiguo. Supabase la entrega justo para esto y da por hecho que será visible dentro de tu app. La librería cliente la pone en la cabecera en cada petición que hace, así que si creas el cliente con la clave publicable nunca escribes la cabecera tú.",{"q":535,"a":536},"¿Es seguro tener mi clave anon en el navegador?","Sí, y tiene que estar ahí para que tu app pueda hablar con tu proyecto. La clave anon solo dice a qué proyecto pertenece una petición; lo que un visitante con ella alcanza de verdad lo deciden las reglas de Row Level Security de tus tablas. Qué claves de API son seguras en tu frontend recorre toda la familia de claves y enseña a leerlas.",{"q":538,"a":539},"Usé la clave service_role y funcionó. ¿Es un problema?","Sí, y es lo que vale la pena resolver hoy. Una clave service_role lleva el atributo BYPASSRLS de Postgres, así que tus políticas nunca se le aplican. Publicada dentro de tu app queda en un archivo que cualquier visitante puede descargar, y quien lo descargue puede leer y escribir cada fila de cada tabla. Rota la clave primero y luego mueve a un servidor aquello que la necesitaba.",{"q":541,"a":542},"¿Cómo sé qué clave pegué?","Lee el principio de la cadena. sb_publishable_ pertenece a tu app y sb_secret_ nunca. Un valor largo que empieza por eyJ es una del par antiguo, y esas dos se ven idénticas, así que hay que mirar dentro: la sección central se descodifica en datos legibles con un campo role, que dice anon o service_role.","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",[545,546,547,548,549,550,551],"no api key found in request","no api key found in request supabase","supabase no encuentra api key","supabase falta cabecera apikey","401 api key invalida supabase","supabase api key no funciona","supabase 401 unauthorized",{},true,"\"No API key found in request\" en Supabase","\u002Fblog\u002Fno-api-key-found-in-request","2026-10-07",{"title":5,"description":524},"blog\u002Fno-api-key-found-in-request",[560,561,562],"\"No API key found in request\" significa que tu petición llegó a Supabase sin la cabecera apikey, así que la rechazaron en la puerta antes de preguntarle nada a tu base de datos.","El arreglo correcto es tu clave publicable en esa cabecera, que es la clave pensada para ser pública. La librería cliente de Supabase la envía por ti en cada petición.","Los dos arreglos a los que la gente recurre en su lugar son la clave secreta y una regla más floja en la tabla. Ambos callan el mensaje, y ambos dejan tus filas legibles para cualquiera que tenga la clave que viaja dentro de tu app.","kV0ytiCZ3bjdNU5wFgHXwrw_TAjEQXOoAnwgRg0a9LU",[565,571,577,583,589,590,596,602,608,614,620,626,632,638,645,651,657,662,668,674,680,686,692,698,704,709,715,721,727,733,739,745,751,757,763,768,774,780,786,792,798,804,810,816,822,828,833,839,845,851,857,863,869,875,881,886,891,897,902,907,913],{"path":566,"title":567,"description":568,"published":569,"category":521,"image":570,"draft":525},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" al subir","\"New row violates row-level security policy for table objects\" significa que tu subida no tiene regla insert. Hacer público el bucket no añade ninguna.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":572,"title":573,"description":574,"published":575,"category":521,"image":576,"draft":525},"\u002Fblog\u002Fbase44-security-scan","Escaneo de seguridad de Base44: lo que solo él ve","El escaneo de seguridad de Base44 revisa siete tipos de problema desde dentro. Esta es la mitad que lee y nadie más puede leer, y la mitad que nunca mira.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":578,"title":579,"description":580,"published":581,"category":521,"image":582,"draft":525},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Tu clave API se filtró. El orden en el que hay que actuar","Una clave API se filtró y no sabes por dónde empezar. No todas las claves de tu frontend lo son, y el orden importa más que la velocidad.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":584,"title":585,"description":586,"published":587,"category":521,"image":588,"draft":525},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sin desactivar RLS","\"Infinite recursion detected in policy for relation\" significa que tu policy preguntó a la tabla que protege. Así se rompe el círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":555,"title":5,"description":524,"published":556,"category":521,"image":543,"draft":525},{"path":591,"title":592,"description":593,"published":594,"category":521,"image":595,"draft":525},"\u002Fblog\u002Fis-base44-safe","¿Es seguro Base44? Lo que vimos en 5.442 apps Base44","¿Es seguro Base44? Pasamos nueve comprobaciones a 5.442 apps Base44 en producción. Casi todas sacaron B por motivos que su dueño nunca eligió.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":597,"title":598,"description":599,"published":600,"category":521,"image":601,"draft":525},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Ocultar una clave API: muévela a una Edge Function de Supabase","Ocultar una clave API significa sacarla del navegador, y una Edge Function de Supabase es el sitio más pequeño donde ponerla. Dos pasos importan más.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":603,"title":604,"description":605,"published":606,"category":521,"image":607,"draft":525},"\u002Fblog\u002Fenv-file-exposed-on-your-server","¿Tu archivo .env está expuesto? Las doce rutas a revisar","¿Tu archivo .env está expuesto en tu propio servidor web? Doce direcciones te lo dicen, y un acierto significa que todo lo que contiene ya es público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":609,"title":610,"description":611,"published":612,"category":521,"image":613,"draft":525},"\u002Fblog\u002Fis-v0-safe","Seguridad de v0: las 1.790 aplicaciones escaneadas sacaron una A","Seguridad de v0, medida en 1.790 aplicaciones v0 en vivo: todas sacaron A. Solo 17 nombraban una base de datos, y eso es casi todo lo que mide la A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":615,"title":616,"description":617,"published":618,"category":521,"image":619,"draft":525},"\u002Fblog\u002Fis-bolt-safe","¿Es seguro Bolt? Lo que vimos en 1.123 aplicaciones Bolt","¿Es seguro Bolt? Pasamos 1.123 aplicaciones Bolt en vivo por nueve comprobaciones. El hosting salió limpio. Los hallazgos eran claves y tablas abiertas dentro.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":621,"title":622,"description":623,"published":624,"category":521,"image":625,"draft":525},"\u002Fblog\u002Fis-supabase-down-or-your-app","¿Supabase está caído o es tu app? Cómo distinguirlo","¿Supabase está caído o es tu app? Un proyecto pausado, una base de datos llena y un fallo tuyo parecen lo mismo. Cuatro comprobaciones los separan.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":627,"title":628,"description":629,"published":630,"category":521,"image":631,"draft":525},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","¿Supabase cifra mis datos? Sí. Esto es lo que detiene","¿Supabase cifra los datos? Sí: AES-256 en reposo, TLS en tránsito, SOC 2 e ISO 27001. Qué cubre cada uno, y la fuga que ninguno de ellos detiene.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":633,"title":634,"description":635,"published":636,"category":521,"image":637,"draft":525},"\u002Fblog\u002Fsupabase-free-plan-limits","¿Cuánto cuesta Supabase? Los límites del plan gratuito","Los límites del plan gratuito de Supabase: 500 MB de base de datos, 5 GB de egress y ningún backup. Qué pasa en cada uno y qué cambia Pro por $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":639,"title":640,"description":641,"published":642,"category":643,"image":644,"draft":525},"\u002Fblog\u002Ftest-your-supabase-backup","Prueba tu backup de Supabase antes del día que lo necesites","Cómo probar tu backup de Supabase: restaurarlo en un proyecto de prueba, contar filas, iniciar sesión y buscar la línea que le falta a un archivo cortado.","2026-09-28","Backups","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":646,"title":647,"description":648,"published":649,"category":643,"image":650,"draft":525},"\u002Fblog\u002Fsupabase-backup-github-action","Backup gratis de Supabase con una GitHub Action, y la trampa","Un backup de Supabase con GitHub Action es gratis y sirve a muchas apps. El workflow, el connection string correcto y el egress de cada ejecución.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":652,"title":653,"description":654,"published":655,"category":643,"image":656,"draft":525},"\u002Fblog\u002Fdownload-your-supabase-backup","Por qué no puedes descargar tu backup de Supabase","No puedes descargar tu backup de Supabase en un proyecto actual: la copia diaria es una instantánea física. Cómo comprobarlo y tener tu propia copia.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":658,"title":659,"description":660,"published":655,"category":521,"image":661,"draft":525},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": el grant que falta","Desde el 30 de octubre, una tabla nueva de Supabase responde \"permission denied for table\" hasta que le das acceso. El grant del email es la mitad del arreglo.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":663,"title":664,"description":665,"published":666,"category":521,"image":667,"draft":525},"\u002Fblog\u002Fopen-api-endpoint-exposed","¿Un endpoint de API abierto es un problema? Mira el JSON","Tu escaneo señaló un endpoint de API abierto. Que importe depende de lo que devolvió, y la mayoría de los que encontramos eran de la plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":669,"title":670,"description":671,"published":672,"category":521,"image":673,"draft":525},"\u002Fblog\u002Flovable-security-scan","Escaneo de seguridad de Lovable: lo que no puede probar","Escaneo de seguridad de Lovable: qué revisan el Quick scan y el Deep scan, cuándo corre cada uno, y lo único que ningún escaneo desde dentro puede probar.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":675,"title":676,"description":677,"published":678,"category":643,"image":679,"draft":525},"\u002Fblog\u002Fsupabase-backup-auth-users","Por qué tu dump de Supabase no tiene usuarios dentro","Ejecuta supabase db dump por sí solo y obtienes la forma de tu base de datos y ninguna de sus filas, sin el esquema auth donde viven tus usuarios.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":681,"title":682,"description":683,"published":684,"category":521,"image":685,"draft":525},"\u002Fblog\u002Fdomain-and-certificate-expiry","Dominio caducado, web caída: qué pasa a partir de ahora","Tu dominio caducó y tu web está caída. Aquí tienes el reloj que acaba de arrancar, por qué el certificado es el menor problema, y cómo comprobar ambos.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":687,"title":688,"description":689,"published":690,"category":521,"image":691,"draft":525},"\u002Fblog\u002Fis-lovable-safe","¿Es seguro Lovable? Lo que vimos en 18.554 aplicaciones Lovable","¿Es seguro Lovable? Pasamos 18.554 aplicaciones Lovable por nueve comprobaciones. La plataforma fue la más limpia de cinco. Los hallazgos estaban dentro.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":693,"title":694,"description":695,"published":696,"category":521,"image":697,"draft":525},"\u002Fblog\u002Fvibe-coded-app-security-checklist","La lista de seguridad del vibe coding, en nueve comprobaciones","Una lista de seguridad del vibe coding con nueve puntos, cada uno verificable en tu app desde fuera por cualquiera, y cada uno con una prueba de una línea.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":699,"title":700,"description":701,"published":702,"category":521,"image":703,"draft":525},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Una clave secreta de Stripe en tu frontend puede mover dinero","Una clave secreta de Stripe expuesta en tu frontend puede reembolsar, cobrar y leer cada ficha de cliente que tienes. Tu clave pk_live_ sí debe estar ahí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":82,"title":705,"description":706,"published":707,"category":521,"image":708,"draft":525},"Variables de entorno de Vite expuestas: el prefijo dice publica esto","Variables de entorno de Vite expuestas en tu app: hicieron lo que pedía el prefijo. VITE_ y NEXT_PUBLIC_ significan publica esto, y la IA nunca supo el coste.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":710,"title":711,"description":712,"published":713,"category":521,"image":714,"draft":525},"\u002Fblog\u002Fbase44-source-maps","Seguridad en Base44: qué marca un escaneo y qué te toca arreglar a ti","Seguridad en Base44 en 5.438 apps escaneadas: tres hallazgos en casi todas son de la plataforma, el source map es la insignia de Base44 y lo tuyo es poco.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":716,"title":717,"description":718,"published":719,"category":521,"image":720,"draft":525},"\u002Fblog\u002Fis-cursor-ai-safe","¿Es seguro Cursor AI? El editor, el código y la app que publicaste","¿Es seguro Cursor AI? Tres preguntas en una búsqueda: qué guarda Cursor, en qué falla el código que escribe y si la app que publicaste está abierta.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":722,"title":723,"description":724,"published":725,"category":521,"image":726,"draft":525},"\u002Fblog\u002Fis-replit-safe","¿Es seguro Replit? Lo que vimos en 3.042 aplicaciones Replit en vivo","¿Es seguro Replit? Pasamos 3.042 aplicaciones Replit en vivo por nueve comprobaciones externas. Los hallazgos estaban en la aplicación publicada, no en el host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":728,"title":729,"description":730,"published":731,"category":643,"image":732,"draft":525},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: tu copia de la base no tiene archivos","Un Supabase storage backup es una tarea aparte. Las copias de la base guardan la lista de tus archivos y ninguno de ellos, así que cada upload queda roto.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":734,"title":735,"description":736,"published":737,"category":643,"image":738,"draft":525},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery de Supabase: precio y límites","El point-in-time recovery de Supabase rebobina tu base de datos a cualquier segundo de la última semana. Cuesta $100 al mes sobre Pro y solo cubre la base.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":740,"title":741,"description":742,"published":743,"category":643,"image":744,"draft":525},"\u002Fblog\u002Fsupabase-project-paused-recover","¿Proyecto de Supabase pausado? Tus datos siguen ahí","Supabase pausó tu proyecto tras una semana sin actividad. No se ha borrado nada, Restaurar está junto al nombre y tienes un año antes de que eso cambie.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":746,"title":747,"description":748,"published":749,"category":521,"image":750,"draft":525},"\u002Fblog\u002Fsafest-ai-app-builder","¿Qué builder de apps con IA es más seguro? 30.998 apps escaneadas","¿Qué builder de apps con IA es más seguro? Escaneamos 30.998 apps activas de Lovable, Base44, Replit, v0 y Bolt. El builder no es lo que decide tu nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":752,"title":753,"description":754,"published":755,"category":521,"image":756,"draft":525},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Activa Row Level Security en cada tabla de Supabase y compruébalo","Activar Row Level Security en Supabase sin política cierra la tabla del todo. Una política sin el interruptor no hace nada. Aquí tienes el SQL y la prueba.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":758,"title":759,"description":760,"published":761,"category":521,"image":762,"draft":525},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": lo que el aviso no ve","Supabase marca \"RLS disabled in public\" como error. No dice nada de la política de lectura que deja tu tabla igual de abierta a cualquiera.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":397,"title":764,"description":765,"published":766,"category":521,"image":767,"draft":525},"Cómo rotar una clave service_role de Supabase filtrada","Supabase dice que primero cierres la fuga. Otras guías dicen que rotes ya. Cuál es lo correcto depende de dónde se filtró tu clave service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":769,"title":770,"description":771,"published":772,"category":521,"image":773,"draft":525},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Escáneres de seguridad vibe coding comparados, el nuestro incluido","El mejor escáner de seguridad para vibe coding depende de tres preguntas que ninguna lista de funciones responde. Diez herramientas, con precios.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":775,"title":776,"description":777,"published":778,"category":521,"image":779,"draft":525},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: haz tú mismo las cinco comprobaciones","Un Supabase security checker lee tu app publicada en lugar de la configuración de tu proyecto. Estas son las cinco comprobaciones y cómo hacer cada una.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":781,"title":782,"description":783,"published":784,"category":521,"image":785,"draft":525},"\u002Fblog\u002Fvibe-coding-security-scanner","Escáner de seguridad para vibe coding: qué se le escapa","Un escáner de seguridad para vibe coding lee tu app en vivo desde fuera. Qué cubre eso, las cuatro cosas que no puede ver y cómo leer el resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":787,"title":788,"description":789,"published":790,"category":521,"image":791,"draft":525},"\u002Fblog\u002Fmissing-security-headers","Faltan cabeceras de seguridad: cuándo importa de verdad","Que falten cabeceras de seguridad es el hallazgo que más imprime nuestro escáner. Contra qué protegen y cuándo son la línea menos urgente de tu informe.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":793,"title":794,"description":795,"published":796,"category":521,"image":797,"draft":525},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Tu clave de API de OpenAI está expuesta en tu frontend. Rótala.","Una clave de API de OpenAI expuesta en tu frontend no se puede atar a un dominio. Rótala hoy, mueve la llamada a tu servidor y limita el gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":799,"title":800,"description":801,"published":802,"category":521,"image":803,"draft":525},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Clave de API expuesta en el frontend: qué llevan 30.998 apps","Una clave de API expuesta en tu frontend suele ser una clave de Google Maps. Escaneamos 30.998 apps vibe-coded y contamos qué secretos se filtran de verdad.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":805,"title":806,"description":807,"published":808,"category":643,"image":809,"draft":525},"\u002Fblog\u002Fsupabase-backup-tools-compared","Herramientas de backup de Supabase comparadas, la nuestra incluida","Cuatro tipos de herramienta de backup de Supabase, qué copia cada una y cuándo una GitHub Action gratuita le gana a pagar a cualquiera, nosotros incluidos.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":811,"title":812,"description":813,"published":814,"category":521,"image":815,"draft":525},"\u002Fblog\u002Freplit-secrets-explained","Cómo usar secrets en Replit, y qué se publica de todos modos","Cómo usar secrets en Replit: añadir uno, leerlo y arreglar las dos causas del undefined. Y las claves que la herramienta Secrets no puede mantener privadas.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":817,"title":818,"description":819,"published":820,"category":643,"image":821,"draft":525},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups del plan gratuito de Supabase: cómo hacer uno sin terminal","No hay backups en el plan gratuito de Supabase: la copia tienes que hacerla tú. Cómo sacarla desde el panel y qué deja fuera la vía CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":823,"title":824,"description":825,"published":826,"category":521,"image":827,"draft":525},"\u002Fblog\u002Fis-supabase-secure","¿Supabase es seguro? Sí. Tu proyecto es otra pregunta","¿Supabase es seguro? La plataforma está auditada, cifrada y sometida a pentests. Su propia documentación dice dónde termina eso y empiezan tus ajustes.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":373,"title":829,"description":830,"published":831,"category":521,"image":832,"draft":525},"Dónde están tus claves API de Supabase: anon, service_role y URL","La URL del proyecto, la clave anon y la clave service_role están en una sola página del panel. Aquí tienes dónde está, y cuál de los cuatro va en tu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":834,"title":835,"description":836,"published":837,"category":521,"image":838,"draft":525},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy en Supabase. ¿Y ahora?","\"New row violates row-level security policy\" significa que Supabase rechazó una escritura. El arreglo rápido vuelve a abrir la tabla para cualquiera.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":840,"title":841,"description":842,"published":843,"category":521,"image":844,"draft":525},"\u002Fblog\u002Fcors-wildcard-security-risk","¿Es un comodín CORS un riesgo de seguridad? Casi nunca.","¿Es un comodín CORS un riesgo de seguridad? Casi siempre es el ajuste por defecto de tu builder y no entrega nada que tu servidor no diera ya a cualquiera.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":846,"title":847,"description":848,"published":849,"category":643,"image":850,"draft":525},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching no es un backup. Solo va hacia adelante.","Por qué el branching de Supabase no es un backup: una rama arranca sin tus datos y un merge solo mueve el esquema. Para qué sirve y qué usar en su lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":852,"title":853,"description":854,"published":855,"category":643,"image":856,"draft":525},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Cómo restaurar un backup de Supabase, y qué se rompe después","Cómo restaurar un backup de Supabase desde el panel o desde un archivo de volcado, qué reemplaza la restauración y por qué tu app puede seguir rota al terminar.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":858,"title":859,"description":860,"published":861,"category":521,"image":862,"draft":525},"\u002Fblog\u002Fsupabase-storage-bucket-public","Tu bucket de Supabase Storage es público. ¿Es un problema?","Un bucket público de Supabase Storage significa que quien tenga la URL de un archivo puede abrirlo. No significa que alguien pueda listar lo que hay dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":864,"title":865,"description":866,"published":867,"category":521,"image":868,"draft":525},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","¿Es un problema una clave de API de Google en tu frontend?","Una clave de API de Google en tu frontend es la clave que más encuentra nuestro escáner, y casi siempre no pasa nada. Un ajuste gratuito decide cuál es cuál.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":870,"title":871,"description":872,"published":873,"category":643,"image":874,"draft":525},"\u002Fblog\u002Fai-agent-deleted-my-database","Un agente de IA borró mis datos de Supabase. ¿Qué puedo recuperar?","Un agente de IA borró datos de tu base. Lo que puedes recuperar ya estaba decidido antes de que se ejecutara, y los próximos minutos deciden el resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":876,"title":877,"description":878,"published":879,"category":521,"image":880,"draft":525},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","¿Puede cualquiera leer tu base de datos Supabase? 3.680 apps","¿Puede cualquiera leer tu base de datos Supabase sin iniciar sesión? Escaneamos 30.998 apps activas hechas con builders de IA y medimos cuántas dicen que sí.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":882,"title":883,"description":884,"published":879,"category":521,"image":885,"draft":525},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expuestos: tu app está publicando su código original","Un source map expuesto deja que cualquiera lea el código original de tu app, comentarios incluidos. La comprobación de 30 segundos y lo que de verdad importa.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":368,"title":887,"description":888,"published":889,"category":521,"image":890,"draft":525},"Las nuevas claves de API de Supabase: ¿cuál va en tu app?","Supabase sustituyó anon y service_role por claves publicables y secretas. ¿Cuál pertenece a tu app y cuál no debe estar nunca?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":892,"title":893,"description":894,"published":895,"category":643,"image":896,"draft":525},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","¿Supabase respalda mi base de datos? Depende de tu plan.","¿Supabase respalda tu base de datos? A diario en los planes de pago, y nada en el gratuito. Cómo saber cuál tienes y qué es lo que esa copia no cubre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":302,"title":898,"description":899,"published":900,"category":521,"image":901,"draft":525},"Supabase Row Level Security está activado. Tu tabla sigue pública.","Activar Supabase Row Level Security no protege una tabla. Lo hacen tus políticas, y la que arregló tu app rota puede dejar entrar a cualquiera.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":903,"title":904,"description":905,"published":900,"category":643,"image":906,"draft":525},"\u002Fblog\u002Fversion-history-is-not-a-backup","El historial de versiones no es un backup. No recupera una tabla.","Lovable y Bolt guardan un historial de versiones de tu código. Tu base de datos es un servicio aparte, y volver atrás no te devuelve tus datos.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":908,"title":909,"description":910,"published":911,"category":643,"image":912,"draft":525},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Tres formas de respaldar una base Supabase, y qué falta en cada una","El panel, pg_dump y un servicio gestionado. Qué guarda de verdad cada uno, qué deja fuera sin avisar y cuál sobrevive a perder la cuenta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":148,"title":914,"description":915,"published":911,"category":521,"image":916,"draft":525},"Qué claves de API son seguras en el navegador y cuáles no","Tu clave anon de Supabase está pensada para ser pública. Tu clave service_role no, y se salta todas las reglas que pongas. Cómo distinguirlas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1791705962955]