[{"data":1,"prerenderedAt":935},["ShallowReactive",2],{"blog-es-aws-access-key-exposed-in-frontend":3,"blog-index-es":406},{"id":4,"title":5,"body":6,"category":363,"cover":364,"coverAlt":365,"description":366,"draft":367,"extension":368,"faq":369,"image":383,"keywords":384,"meta":393,"navigation":394,"ogTitle":395,"path":396,"published":397,"seo":398,"stem":399,"tldr":400,"updated":397,"__hash__":405},"blog_es\u002Fblog\u002Faws-access-key-exposed-in-frontend.md","Una clave AWS expuesta en tu frontend no es como una clave OpenAI",{"type":7,"value":8,"toc":350},"minimark",[9,18,21,26,39,45,59,65,69,72,79,85,91,97,100,104,107,110,116,119,128,132,135,138,141,150,155,159,162,171,198,209,217,221,224,227,238,241,245,251,260,280,290,307,310,314,337],[10,11,12,13,17],"p",{},"Alguien abre tu aplicación en un navegador, pulsa F12 y encuentra una cadena\nque empieza por ",[14,15,16],"code",{},"AKIA"," dentro de tu código de frontend. O GitHub te escribe\npara decirte que un commit que subiste en marzo lleva una credencial de AWS. El\nconsejo que llega con cualquiera de las dos cosas es siempre el mismo: rota la\nclave. Para la mayoría de las claves esa es casi toda la respuesta.",[10,19,20],{},"Aquí está la parte que guía tras guía se equivoca. Una clave de acceso de AWS\nexpuesta en tu frontend no es una clave que gasta dinero. Es una clave que abre\ncosas, y las dos salen mal en direcciones distintas. Una clave que solo gasta\nes una tarjeta de empresa: alguien hace una cuenta, tú anulas la tarjeta, y el\ndaño es una cifra que puedes leer en un extracto. Una clave que abre cosas es\nel manojo de llaves del almacén. Lo que alcanza depende de lo que le escribieron\nencima cuando la cortaron, y eso se lee en una sola pantalla de tu consola de\nAWS.",[22,23,25],"h2",{"id":24},"qué-significa-akia-al-principio-de-una-clave","¿Qué significa AKIA al principio de una clave?",[10,27,28,29,31,32,35,36,38],{},"Marca una clave de acceso de larga duración, que pertenece a un usuario de tu\ncuenta o al acceso root de la cuenta. AWS anota el prefijo en su propia\nreferencia de identificadores: ",[14,30,16],{}," para claves de acceso y ",[14,33,34],{},"ASIA"," para las\ntemporales que reparte su servicio de tokens. Así que los cuatro primeros\ncaracteres te dicen con cuál estás tratando, y ",[14,37,16],{}," es la que no caduca.\nFunciona hasta que alguien la apaga.",[10,40,41,42,44],{},"Una credencial de AWS son dos cadenas, y una petición necesita las dos para ir\nfirmada. La primera es el identificador de la clave de acceso, la parte que\nempieza por ",[14,43,16],{},". La segunda es la clave de acceso secreta, una cadena más\nlarga sin ningún prefijo delante. El identificador por sí solo no firma nada.",[10,46,47,48,50,51,54,55,58],{},"Vale la pena comprobarlo antes de decidir lo mala que es esta mañana, porque\ncambia la respuesta. Si tu bundle lleva la cadena ",[14,49,16],{}," y nada que se parezca\na su mitad secreta, un visitante que leyó tu página se llevó el nombre de la\nllave y no la llave. En la práctica las dos viajan juntas, porque lo que metió\nuna en el navegador metió las dos: un par de variables de entorno llamadas\n",[14,52,53],{},"AWS_ACCESS_KEY_ID"," y ",[14,56,57],{},"AWS_SECRET_ACCESS_KEY",", leídas por código que debía\nejecutarse en un servidor.",[60,61],"diagram",{"alt":62,"caption":63,"src":64},"Dos valores apilados a la izquierda: uno corto en turquesa que dice AKIA y, debajo, otro más largo cuyo contenido está dibujado como bloques tachados. Los dos se juntan en una flecha hacia un documento con un sello en forma de llave, marcado con un tic. Bajo una línea divisoria, el valor AKIA solo lleva a una cruz.","Las dos mitades juntas firman una petición. El identificador por sí solo es un nombre, y un nombre no abre nada.","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Ftwo-strings-one-signature-1600x640.png",[22,66,68],{"id":67},"qué-puede-hacer-alguien-con-mi-clave-de-acceso-de-aws","¿Qué puede hacer alguien con mi clave de acceso de AWS?",[10,70,71],{},"Lo que permitan sus permisos, y nada más allá. Así que hay tres respuestas.",[10,73,74,78],{},[75,76,77],"strong",{},"¿Qué puede leer?"," Cada bucket de S3 que liste la política, y cada objeto\ndentro, incluidos aquellos a los que nunca has enlazado desde ningún sitio. Un\nbucket que nada de tu aplicación menciona no está escondido de una credencial\nque puede listarlo.",[10,80,81,84],{},[75,82,83],{},"¿Qué puede escribir?"," Los mismos sitios, y esa es la mitad que se olvida.\nUna clave que puede escribir también puede sobrescribir y borrar, y un archivo\nsustituido en el sitio se ve exactamente igual que el que tú subiste hasta que\nalguien lo abre.",[10,86,87,90],{},[75,88,89],{},"¿Qué puede arrancar?"," Esta es la que lleva contador. Una política lo bastante\namplia para lanzar cómputo lanza cómputo, y eso factura por hora mientras siga\nfuncionando. Nada de la copia que tiene el navegador limita qué parte de tu\ncuenta alcanza; la política es el único límite que hay.",[10,92,93,94,96],{},"La peor versión de esto es una clave cortada para el acceso root de la cuenta.\nAWS dice en sus propias indicaciones sobre el usuario root que ese usuario\ntiene acceso sin restricciones a todos los servicios de AWS, a los recursos y a\nlos datos de facturación, y desaconseja crearle claves de acceso. Si la clave\nde tu página empieza por ",[14,95,16],{}," y pertenece al usuario root, lo expuesto es la\ncuenta entera y no un bucket.",[10,98,99],{},"Así que no adivines nada de esto. Abre IAM, busca el usuario al que pertenece\nla clave y lee las políticas que lleva asociadas. Es una pantalla, y responde a\nlas tres preguntas de arriba.",[22,101,103],{"id":102},"basta-con-rotarla","¿Basta con rotarla?",[10,105,106],{},"Desactiva hoy la clave expuesta, y no pongas un recambio en el mismo sitio.",[10,108,109],{},"Desactivar es el primer movimiento correcto y es más suave de lo que suena. AWS\ndeja que un usuario tenga hasta dos claves de acceso activas a la vez, y eso\nexiste justamente para que un recambio suba antes de que la vieja baje.\nDesactivar deja la clave ahí y apagada, y se puede volver a encender; borrar es\nirreversible, y la mitad secreta de una clave borrada no se recupera. Así que\ndesactiva, mira qué se rompe y borra después.",[10,111,112,113,115],{},"Lo que no cierra el asunto es crear una clave nueva y pegarla donde estaba la\nvieja. La filtración nunca fue realmente por ese valor concreto. Fue porque un\nnavegador tenía una credencial que no caduca, y todo lo que tu página descarga\nlo descarga cada visitante. Una cadena ",[14,114,16],{}," recién hecha en el mismo bundle\nvuelve como el mismo hallazgo en el siguiente escaneo.",[10,117,118],{},"AWS lo dice con claridad en su guía de auditoría de seguridad, hablando de\naplicaciones móviles: nunca deberían llevar claves de acceso incrustadas, ni\nsiquiera cifradas. Un bundle de navegador se lee más fácil que un binario de\naplicación, así que la misma respuesta vale aquí y le cuesta menos trabajo a un\ndesconocido.",[10,120,121,122,127],{},"Si ya has encontrado la clave en un sitio público, el orden en el que trabajas\nimporta, y\n",[123,124,126],"a",{"href":125},"\u002Fblog\u002Fapi-key-leaked-what-to-do","qué hacer cuando se filtra una clave de API","\ndeja ese orden puesto para claves de todo tipo.",[22,129,131],{"id":130},"qué-hace-una-presigned-url-en-su-lugar","Qué hace una presigned URL en su lugar",[10,133,134],{},"Deja que el navegador haga una sola cosa con un solo archivo sin tener ninguna\ncredencial.",[10,136,137],{},"Tu propio servidor se queda con la clave de acceso, donde un visitante no puede\nleerla. Cuando tu página tiene que dejar un archivo en S3 o sacar uno, se lo\npide a tu servidor, y tu servidor firma una URL para ese objeto y esa acción y\nse la devuelve. El navegador usa la URL y no se lleva nada más con ella. AWS\ndescribe una presigned URL como acceso temporal a objetos de S3 sin\ncredenciales de AWS, y el mismo mecanismo cubre descargas y subidas.",[10,139,140],{},"Volvamos al almacén. Una presigned URL es recibir al mensajero en la puerta con\nla caja que venía a buscar, en lugar de darle el manojo y confiar en que la\nencuentre. Lo que el mensajero se lleva deja de funcionar cuando su reloj se\nacaba.",[10,142,143,144,146,147,149],{},"Para el caso en que cada persona con sesión llega a sus propios archivos, AWS\nseñala otra vez a otro sitio: sus indicaciones sobre asegurar claves de acceso\ndicen que las aplicaciones móviles deberían usar Amazon Cognito para gestionar\nidentidades en lugar de incrustar claves de acceso. Lo que Cognito da al\nnavegador es una credencial temporal, la clase ",[14,145,34],{}," del principio de este\nartículo, que deja de funcionar sola al cabo de un rato. Una copia sacada de tu\npágina un martes ya está muerta el miércoles, y esa es la única propiedad que\nuna clave ",[14,148,16],{}," no tiene.",[60,151],{"alt":152,"caption":153,"src":154},"Dos recorridos dibujados uno encima del otro. Arriba, un navegador con una llave al lado, una flecha y una estantería de ocho archivos en dos baldas. Abajo, el mismo navegador, una flecha hacia un servidor que guarda la llave, y otra flecha hacia un único archivo con una esfera de reloj al lado.","El recorrido de arriba pone en el navegador algo que sirve para cada archivo, mañana igual que hoy. El de abajo le da un archivo y un plazo.","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fkey-or-url-1600x700.png",[22,156,158],{"id":157},"cómo-compruebo-si-mi-aplicación-envía-una-clave-de-aws","¿Cómo compruebo si mi aplicación envía una clave de AWS?",[10,160,161],{},"Busca en lo que el navegador se ha descargado, no en lo que hay en tu proyecto.\nSon dos archivos distintos, y el que cuenta es el que reciben tus visitantes.",[10,163,164,167,168,170],{},[75,165,166],{},"En el navegador."," Abre tu sitio publicado, pulsa F12 y busca ",[14,169,16],{}," en el\nJavaScript cargado. Chrome y Edge buscan en todos los archivos cargados a la\nvez desde el panel Sources.",[10,172,173,176,177,179,180,182,183,185,186,54,189,192,193,197],{},[75,174,175],{},"En tu proyecto."," Busca ",[14,178,16],{},", ",[14,181,53],{}," y\n",[14,184,57],{},". Luego busca los dos prefijos que meten un valor en un\nbundle a propósito, ",[14,187,188],{},"VITE_",[14,190,191],{},"NEXT_PUBLIC_",", y lee cada valor que haya detrás.\n",[123,194,196],{"href":195},"\u002Fblog\u002Fvite-and-next-public-env-vars","Por qué esos dos prefijos publican todo lo que nombran","\nes la mecánica que hay detrás de casi todos estos casos, y es una regla del\nbuild que nadie tecleó por error.",[10,199,200,203,204,208],{},[75,201,202],{},"Desde fuera."," Nuestro escaneo gratuito lee tu sitio publicado como lo haría\nun desconocido y dice qué credenciales ve en lo que has publicado, esta\nincluida. Tarda unos 20 segundos y no pide cuenta:\n",[123,205,207],{"href":206},"\u002Fsecurity-scanner","escanea tu aplicación gratis",".",[10,210,211,212,216],{},"De todas las aplicaciones que hemos escaneado, este es un hallazgo raro: una\nclave de acceso de AWS apareció en 9 de las 31.056 aplicaciones donde esa\ncomprobación llegó hasta el final. Las que salen mucho más a menudo son las de\nGoogle, que suelen estar bien, y las de OpenAI, que suelen no estarlo.\n",[123,213,215],{"href":214},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Qué se escapa de verdad de las aplicaciones hechas así","\nlas pone todas una al lado de otra con las cifras.",[22,218,220],{"id":219},"qué-hizo-la-clave-mientras-estuvo-fuera","Qué hizo la clave mientras estuvo fuera",[10,222,223],{},"Abre el historial de eventos de CloudTrail y fíltralo por el identificador de\nla clave de acceso.",[10,225,226],{},"El historial de eventos está encendido en toda cuenta de AWS sin tener que\nactivar nada, guarda los últimos 90 días y no cuesta nada aparte. Cada entrada\nlleva el identificador de la clave que hizo la llamada, así que puedes releer\nlo que hizo la tuya. Eso responde a las preguntas de configuración: un bucket\ncreado, una política cambiada, un usuario añadido.",[10,228,229,230,233,234,237],{},"Luego está la parte que conviene saber antes de ponerse a mirar. El historial\nguarda eventos de ",[75,231,232],{},"management",". Leer un objeto de S3 es un evento de\n",[75,235,236],{},"data",", y AWS dice explícitamente que los trails no los registran por defecto\ny que los eventos de data no aparecen en el historial. Encenderlos graba a\npartir de ese momento.",[10,239,240],{},"Así que la lectura honesta es esta. Si la clave se usó para cambiar tu cuenta,\nel registro te lo enseña. Si se usó para descargar el contenido de un bucket,\nprobablemente no, y estás decidiendo qué contarles a tus clientes sabiendo que\npudo pasar.",[22,242,244],{"id":243},"cómo-dejar-una-clave-fuera-del-siguiente-build","Cómo dejar una clave fuera del siguiente build",[10,246,247,250],{},[75,248,249],{},"Una credencial sale hacia el navegador en el momento del build, así que el\nsiguiente despliegue es el que hay que vigilar."," La clave que quitas hoy\nvuelve la tarde en que alguien añade una función que necesita S3 y le pide a un\nagente que la conecte.",[10,252,253],{},[75,254,255,259],{},[123,256,258],{"href":257},"\u002Fwebsite-monitoring","Reeve Monitor"," vuelve a leer tu sitio publicado por ti:",[261,262,263,267,274,277],"ul",{},[264,265,266],"li",{},"las nueve comprobaciones cada hora, en hasta tres aplicaciones",[264,268,269,270,273],{},"un mensaje cuando un resultado ",[75,271,272],{},"cambia",", para que una clave que llega un martes no espere a que mires",[264,275,276],{},"si la aplicación responde, cada 60 segundos",[264,278,279],{},"un informe mensual de lo que vio",[10,281,282],{},[75,283,284,285,289],{},"Si tu aplicación guarda sus datos en un proyecto de Supabase,\n",[123,286,288],{"href":287},"\u002Fsupabase-backups","Reeve Care"," también guarda una copia:",[261,291,292,295,298,301,304],{},[264,293,294],{},"una copia cifrada de tu base de datos de Supabase cada noche, guardada donde tu proyecto no llega",[264,296,297],{},"cada copia verificada antes de contar, contando las filas de cada tabla",[264,299,300],{},"una restauración con un clic cuando la necesitas",[264,302,303],{},"también tus archivos subidos, en cuanto conectas una credencial de Storage",[264,305,306],{},"todo lo que hace Monitor",[10,308,309],{},"Cada una de esas nueve comprobaciones describe lo que un desconocido puede\nalcanzar. Una copia de la base de datos de anoche responde a la otra pregunta,\nla de qué cambió ya alguien mientras la clave estuvo fuera.",[22,311,313],{"id":312},"qué-hacer-esta-semana","Qué hacer esta semana",[315,316,317],"key-takeaways",{},[261,318,319,325,328,331,334],{},[264,320,321,322,324],{},"Abre tu sitio publicado, pulsa F12 y busca ",[14,323,16],{}," en el JavaScript cargado. Ese es el archivo que tienen tus visitantes, y es el único que cuenta.",[264,326,327],{},"Si encuentras una, desactívala hoy en IAM. Desactivar es reversible y surte efecto al momento; borrar no lo es, y la mitad secreta no se recupera.",[264,329,330],{},"Lee las políticas asociadas al usuario de la clave antes de decidir lo serio que es esto. Qué puede leer, qué puede escribir y qué puede arrancar son tres respuestas separadas.",[264,332,333],{},"Cambia el patrón en vez del valor. Tu servidor guarda la clave y firma una presigned URL para un objeto, o Amazon Cognito le da al navegador una credencial temporal que caduca sola.",[264,335,336],{},"Filtra el historial de eventos de CloudTrail por la clave en los últimos 90 días. Te enseñará qué configuró la clave, y no te enseñará qué archivos leyó salvo que los eventos de data ya estuvieran encendidos.",[10,338,339,340,344,345,349],{},"Empieza por la búsqueda con F12, porque en un minuto resuelve si siquiera\ntienes un problema. Si saca algo, la\n",[123,341,343],{"href":342},"\u002Fchecklist","lista de seguridad de 10 minutos"," cubre el resto de lo que una\naplicación recién lanzada suele dejar abierto, y\n",[123,346,348],{"href":347},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","mover un secreto a una edge function","\nes el patrón para cada clave que nunca debió estar en la página.",{"title":351,"searchDepth":352,"depth":352,"links":353},"",3,[354,356,357,358,359,360,361,362],{"id":24,"depth":355,"text":25},2,{"id":67,"depth":355,"text":68},{"id":102,"depth":355,"text":103},{"id":130,"depth":355,"text":131},{"id":157,"depth":355,"text":158},{"id":219,"depth":355,"text":220},{"id":243,"depth":355,"text":244},{"id":312,"depth":355,"text":313},"Fundamentos de seguridad","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcover-1200x630.png","Una página de código de aplicación con un valor corto encendido y otro largo tapado, una llave cruzada sobre su esquina y, detrás, una estantería de archivos.","Una clave de acceso de AWS expuesta en tu frontend lee y escribe tu almacenamiento. La solución suele ser una presigned URL, no una clave nueva.",false,"md",[370,373,375,378,380],{"q":371,"a":372},"¿Alguna vez es seguro poner claves de AWS en el código del frontend?","No. AWS lo dice en su propia guía de auditoría de seguridad, hablando de aplicaciones móviles: una aplicación nunca debería llevar claves de acceso incrustadas, ni siquiera cifradas. Un bundle de navegador se lee más fácil que un binario de aplicación, así que la misma respuesta vale aquí y le cuesta menos trabajo a un desconocido. Si tu página de verdad tiene que llegar a S3, las vías previstas son una presigned URL firmada por tu propio servidor, o credenciales temporales de Amazon Cognito, que caducan solas.",{"q":68,"a":374},"Exactamente lo que permitan sus permisos, y por eso no hay una sola respuesta. Una clave puesta en un usuario con acceso de lectura a un bucket lee ese bucket. Una clave puesta en un administrador hace todo lo que hace un administrador, incluido arrancar máquinas que facturan por hora. Una clave del usuario root de la cuenta es el peor caso, porque AWS dice que el usuario root tiene acceso sin restricciones a todos los servicios, recursos y datos de facturación. Abre IAM y lee las políticas asociadas a la clave antes de decidir cuánto preocuparte.",{"q":376,"a":377},"¿Qué es una presigned URL?","Una URL larga que deja a un navegador hacer una sola cosa con un solo archivo de S3, durante un número fijo de segundos, sin tener ninguna credencial de AWS. Tu propio servidor guarda la clave y firma la URL cuando se la piden. AWS describe las presigned URLs como acceso temporal a objetos de S3 sin credenciales de AWS, y sirven igual para descargas que para subidas.",{"q":158,"a":379},"Busca en lo que tu navegador se ha descargado, no en lo que hay en tu proyecto. Abre tu sitio publicado, pulsa F12 y busca AKIA en el JavaScript cargado. Luego busca en tu proyecto AKIA, AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY, y cualquier nombre de variable que empiece por VITE_ o NEXT_PUBLIC_ y lleve una, porque esos prefijos son lo que mete un valor en el bundle de entrada.",{"q":381,"a":382},"Mi clave de AWS está en GitHub. ¿Y ahora qué?","Desactívala primero en IAM, que es reversible y surte efecto al momento, y luego crea un recambio para el servidor que la necesitaba. Quitarla del código no cierra nada, porque el valor antiguo sigue en tu historial de commits y en cada clon que alguien se haya llevado. Después abre el historial de eventos de CloudTrail y filtra por la clave para ver qué hizo.","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",[385,386,387,388,389,390,391,392],"clave de acceso aws expuesta en el frontend","clave aws en el frontend","clave de acceso aws filtrada","clave akia expuesta","aws secret access key en javascript","credenciales aws en el cliente","es seguro usar claves aws en react","clave aws en github",{},true,"¿Clave de acceso de AWS expuesta en tu frontend?","\u002Fblog\u002Faws-access-key-exposed-in-frontend","2026-10-12",{"title":5,"description":366},"blog\u002Faws-access-key-exposed-in-frontend",[401,402,403,404],"Una clave de acceso de AWS expuesta en tu frontend es un problema distinto al de una clave que solo puede gastar dinero. Lo que alcanza lo deciden sus permisos.","Dos cadenas firman una petición de AWS: un identificador que empieza por `AKIA`, y una mitad secreta. Una sin la otra no firma nada.","Una clave nueva pegada en el mismo sitio es el mismo hallazgo con otro valor. La solución es una presigned URL, para que el navegador no tenga ninguna credencial.","Encontramos una en 9 de las 31.056 aplicaciones escaneadas donde esa comprobación llegó hasta el final.","vKaqd5EzEgROGs_erINRQRHy368n0Mgo1xRgUvyMZj0",[407,413,419,425,431,437,443,449,455,461,467,474,480,486,492,498,504,510,516,522,528,534,540,546,552,558,564,570,576,577,583,589,594,600,606,612,617,623,629,635,641,647,653,659,665,671,676,682,688,694,700,706,712,718,723,729,735,741,747,753,759,765,771,777,783,789,795,801,807,813,818,824,830,836,842,848,854,860,866,872,878,884,890,896,901,907,913,919,924,930],{"path":408,"title":409,"description":410,"published":411,"category":363,"image":412,"draft":367},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": el pooler no tiene sitio para un cliente más. El puerto de tu cadena de conexión decide el límite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":414,"title":415,"description":416,"published":417,"category":363,"image":418,"draft":367},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Error de Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": Google está desactivado en tu proyecto Supabase. Cómo activarlo y arreglar redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":420,"title":421,"description":422,"published":423,"category":363,"image":424,"draft":367},"\u002Fblog\u002Fviolates-foreign-key-constraint","Error de Supabase \"violates foreign key constraint\" al insertar","Supabase \"insert or update on table violates foreign key constraint\": tu fila apunta a una fila que no existe. Cuál, por qué, y cómo arreglarlo.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":426,"title":427,"description":428,"published":429,"category":363,"image":430,"draft":367},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Error de Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": una columna obligatoria llegó vacía. De dónde vino el null, y cómo arreglarlo.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":432,"title":433,"description":434,"published":435,"category":363,"image":436,"draft":367},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": adónde fue la sesión","\"Auth session missing!\" es supabase-js sin encontrar ninguna sesión iniciada y sin llegar a preguntar a Supabase. Adónde fue la sesión, y el arreglo.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":438,"title":439,"description":440,"published":441,"category":363,"image":442,"draft":367},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": no hay nadie conectado","\"invalid claim: missing sub claim\": Supabase Auth recibió un token auténtico sin ningún usuario, la clave del proyecto en lugar de una sesión.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":444,"title":445,"description":446,"published":447,"category":363,"image":448,"draft":367},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": la causa real","\"Failed to send a request to the Edge Function\": el navegador no recibió una respuesta legible. Su consola dice por qué y si tu función se ejecutó.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":450,"title":451,"description":452,"published":453,"category":363,"image":454,"draft":367},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por qué los enlaces de email de Supabase redirigen a localhost:3000","Si Supabase redirige a localhost:3000, la Site URL nunca se cambió o tu dirección falta en Redirect URLs. La solución, y el comodín que debes evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":456,"title":457,"description":458,"published":459,"category":363,"image":460,"draft":367},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" con un enlace nuevo","Con un enlace enviado hace un minuto, \"Email link is invalid or has expired\" en Supabase suele indicar que un filtro de correo lo usó antes. Cómo arreglarlo.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":462,"title":463,"description":464,"published":465,"category":363,"image":466,"draft":367},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": una consulta superó el límite de su rol, 3 segundos para un visitante. Revisa antes la política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":468,"title":469,"description":470,"published":471,"category":472,"image":473,"draft":367},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" en Supabase, y qué se va con él","\"Database error deleting user\" en Supabase: tu base de datos rechazó el borrado. La causa está en tus logs y el arreglo decide qué más se borra.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":475,"title":476,"description":477,"published":478,"category":363,"image":479,"draft":367},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" en Supabase","¿Tu webhook de Stripe en una Edge Function de Supabase dice \"No signatures found matching the expected signature\"? Tiene dos causas. Sigue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":481,"title":482,"description":483,"published":484,"category":363,"image":485,"draft":367},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" en Supabase: las tres causas","Supabase dice \"Invalid login credentials\" ante una contraseña errónea, un email desconocido y una cuenta de Google. Cómo saber cuál es.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":487,"title":488,"description":489,"published":490,"category":363,"image":491,"draft":367},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": el error real","\"Edge Function returned a non-2xx status code\" significa que tu función de Supabase respondió con un error. Aquí ves dónde leer el real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":493,"title":494,"description":495,"published":496,"category":363,"image":497,"draft":367},"\u002Fblog\u002Fcertificate-not-trusted","Certificado no confiable: tres causas aparte de la caducidad","¿Certificado no confiable aunque la fecha está bien? Nombra otra dirección, se firmó a sí mismo o a su cadena le falta un eslabón. Cómo saber cuál.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":499,"title":500,"description":501,"published":502,"category":363,"image":503,"draft":367},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": lee las comillas","Supabase \"invalid input syntax for type uuid\" significa que tu app envió algo que no es un id. Lee las comillas, frena la consulta, conserva la columna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":505,"title":506,"description":507,"published":508,"category":363,"image":509,"draft":367},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": el valor ya está ocupado. Encuentra la columna, elige un arreglo y aparta el valor de la pantalla.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":511,"title":512,"description":513,"published":514,"category":363,"image":515,"draft":367},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" aunque la tabla está ahí","Supabase \"relation does not exist\" o PGRST205: ninguna tabla tiene ese nombre en ese esquema. Cuatro comprobaciones, y lo que abre exponer un esquema.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":517,"title":518,"description":519,"published":520,"category":363,"image":521,"draft":367},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" muestra los nombres de argumentos que envió tu app. Compáralos con la función.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":523,"title":524,"description":525,"published":526,"category":363,"image":527,"draft":367},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" suele ser un nombre que no coincide. Cuatro comprobaciones y la línea que recarga.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":529,"title":530,"description":531,"published":532,"category":363,"image":533,"draft":367},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dos límites, un solo código","Supabase \"Email Rate Limit Exceeded\" limita cada email que envía tu proyecto: 2 por hora con el remitente integrado. Qué cuenta y cómo subirlo.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":535,"title":536,"description":537,"published":538,"category":363,"image":539,"draft":367},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" cierra la sesión de tus usuarios. Tres causas, y cómo las separa el log de Auth.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":541,"title":542,"description":543,"published":544,"category":363,"image":545,"draft":367},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": tres causas","Supabase \"permission denied for schema public\" es un grant que falta en el esquema. Qué lo quitó y la línea que lo devuelve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":547,"title":548,"description":549,"published":550,"category":363,"image":551,"draft":367},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": las tres cosas que significa","Supabase \"Bucket not found\" es una de tres cosas: un enlace público a un bucket privado, un nombre que no coincide exactamente o el proyecto equivocado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":553,"title":554,"description":555,"published":556,"category":363,"image":557,"draft":367},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: ¿qué clave dejó de funcionar?","Un error Supabase invalid JWT es PGRST301: un token firmado no pasó la verificación. En un proyecto nuevo se trata de la sesión, no de la clave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":559,"title":560,"description":561,"published":562,"category":363,"image":563,"draft":367},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" casi siempre es ninguna","Supabase devuelve PGRST116, \"JSON object requested, multiple (or no) rows returned\", cuando tu consulta no encontró nada. Una fila oculta parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":565,"title":566,"description":567,"published":568,"category":363,"image":569,"draft":367},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" en Supabase: dónde mirar","\"Database error saving new user\" significa que algo unido a tu registro de Supabase falló y se deshizo entero. El error real está en tus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":571,"title":572,"description":573,"published":574,"category":363,"image":575,"draft":367},"\u002Fblog\u002Fwhat-is-supabase","¿Qué es Supabase? La base de datos que eligió tu builder","Qué es Supabase: la base de datos, el login y el almacenamiento de archivos de tu app. Supabase lleva los servidores; las reglas sobre tus filas son tuyas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":396,"title":5,"description":366,"published":397,"category":363,"image":383,"draft":367},{"path":578,"title":579,"description":580,"published":581,"category":363,"image":582,"draft":367},"\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":584,"title":585,"description":586,"published":587,"category":363,"image":588,"draft":367},"\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":125,"title":590,"description":591,"published":592,"category":363,"image":593,"draft":367},"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":595,"title":596,"description":597,"published":598,"category":363,"image":599,"draft":367},"\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":601,"title":602,"description":603,"published":604,"category":363,"image":605,"draft":367},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" en Supabase, y el arreglo equivocado","\"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.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":607,"title":608,"description":609,"published":610,"category":363,"image":611,"draft":367},"\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":347,"title":613,"description":614,"published":615,"category":363,"image":616,"draft":367},"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":618,"title":619,"description":620,"published":621,"category":363,"image":622,"draft":367},"\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":624,"title":625,"description":626,"published":627,"category":363,"image":628,"draft":367},"\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":630,"title":631,"description":632,"published":633,"category":363,"image":634,"draft":367},"\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":636,"title":637,"description":638,"published":639,"category":363,"image":640,"draft":367},"\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":642,"title":643,"description":644,"published":645,"category":363,"image":646,"draft":367},"\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":648,"title":649,"description":650,"published":651,"category":363,"image":652,"draft":367},"\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":654,"title":655,"description":656,"published":657,"category":472,"image":658,"draft":367},"\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","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":660,"title":661,"description":662,"published":663,"category":472,"image":664,"draft":367},"\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":666,"title":667,"description":668,"published":669,"category":472,"image":670,"draft":367},"\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":672,"title":673,"description":674,"published":669,"category":363,"image":675,"draft":367},"\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":677,"title":678,"description":679,"published":680,"category":363,"image":681,"draft":367},"\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":683,"title":684,"description":685,"published":686,"category":363,"image":687,"draft":367},"\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":689,"title":690,"description":691,"published":692,"category":472,"image":693,"draft":367},"\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":695,"title":696,"description":697,"published":698,"category":363,"image":699,"draft":367},"\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":701,"title":702,"description":703,"published":704,"category":363,"image":705,"draft":367},"\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":707,"title":708,"description":709,"published":710,"category":363,"image":711,"draft":367},"\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":713,"title":714,"description":715,"published":716,"category":363,"image":717,"draft":367},"\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":195,"title":719,"description":720,"published":721,"category":363,"image":722,"draft":367},"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":724,"title":725,"description":726,"published":727,"category":363,"image":728,"draft":367},"\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":730,"title":731,"description":732,"published":733,"category":363,"image":734,"draft":367},"\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":736,"title":737,"description":738,"published":739,"category":363,"image":740,"draft":367},"\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":742,"title":743,"description":744,"published":745,"category":472,"image":746,"draft":367},"\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":748,"title":749,"description":750,"published":751,"category":472,"image":752,"draft":367},"\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":754,"title":755,"description":756,"published":757,"category":472,"image":758,"draft":367},"\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":760,"title":761,"description":762,"published":763,"category":363,"image":764,"draft":367},"\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":766,"title":767,"description":768,"published":769,"category":363,"image":770,"draft":367},"\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":772,"title":773,"description":774,"published":775,"category":363,"image":776,"draft":367},"\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":778,"title":779,"description":780,"published":781,"category":363,"image":782,"draft":367},"\u002Fblog\u002Frotate-supabase-service-role-key","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":784,"title":785,"description":786,"published":787,"category":363,"image":788,"draft":367},"\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. Ocho herramientas, con precios.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":790,"title":791,"description":792,"published":793,"category":363,"image":794,"draft":367},"\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":796,"title":797,"description":798,"published":799,"category":363,"image":800,"draft":367},"\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":802,"title":803,"description":804,"published":805,"category":363,"image":806,"draft":367},"\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":808,"title":809,"description":810,"published":811,"category":363,"image":812,"draft":367},"\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":214,"title":814,"description":815,"published":816,"category":363,"image":817,"draft":367},"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":819,"title":820,"description":821,"published":822,"category":472,"image":823,"draft":367},"\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":825,"title":826,"description":827,"published":828,"category":363,"image":829,"draft":367},"\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":831,"title":832,"description":833,"published":834,"category":472,"image":835,"draft":367},"\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":837,"title":838,"description":839,"published":840,"category":363,"image":841,"draft":367},"\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":843,"title":844,"description":845,"published":846,"category":363,"image":847,"draft":367},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","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":849,"title":850,"description":851,"published":852,"category":363,"image":853,"draft":367},"\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":855,"title":856,"description":857,"published":858,"category":363,"image":859,"draft":367},"\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":861,"title":862,"description":863,"published":864,"category":472,"image":865,"draft":367},"\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":867,"title":868,"description":869,"published":870,"category":472,"image":871,"draft":367},"\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":873,"title":874,"description":875,"published":876,"category":363,"image":877,"draft":367},"\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":879,"title":880,"description":881,"published":882,"category":363,"image":883,"draft":367},"\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":885,"title":886,"description":887,"published":888,"category":472,"image":889,"draft":367},"\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":891,"title":892,"description":893,"published":894,"category":363,"image":895,"draft":367},"\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":897,"title":898,"description":899,"published":894,"category":363,"image":900,"draft":367},"\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":902,"title":903,"description":904,"published":905,"category":363,"image":906,"draft":367},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ¿es la misma que la anon key?","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":908,"title":909,"description":910,"published":911,"category":472,"image":912,"draft":367},"\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":914,"title":915,"description":916,"published":917,"category":363,"image":918,"draft":367},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","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":920,"title":921,"description":922,"published":917,"category":472,"image":923,"draft":367},"\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":925,"title":926,"description":927,"published":928,"category":472,"image":929,"draft":367},"\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":931,"title":932,"description":933,"published":928,"category":363,"image":934,"draft":367},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","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",1794213645343]