[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"blog-es-missing-security-headers":3,"blog-index-es":418},{"id":4,"title":5,"body":6,"category":374,"cover":375,"coverAlt":376,"description":377,"draft":378,"extension":379,"faq":380,"image":396,"keywords":397,"meta":405,"navigation":406,"ogTitle":407,"path":408,"published":409,"seo":410,"stem":411,"tldr":412,"updated":409,"__hash__":417},"blog_es\u002Fblog\u002Fmissing-security-headers.md","Faltan cabeceras de seguridad: cuándo importa de verdad",{"type":7,"value":8,"toc":362},"minimark",[9,13,21,30,35,38,41,44,47,51,54,57,63,70,73,76,83,87,90,179,192,196,199,202,207,210,215,227,231,234,237,252,261,265,268,283,293,296,308,312,349],[10,11,12],"p",{},"Tu escaneo vuelve y casi todas las líneas están en verde. Una está en ámbar:\nfaltan algunas cabeceras de seguridad del navegador. Es lo único de la página que\ntiene color, así que parece lo primero de lo que hay que ocuparse.",[10,14,15,16,20],{},"Aquí está la parte que la mayoría de los consejos sobre esto se equivocan. ",[17,18,19],"strong",{},"Que\nfalten cabeceras de seguridad es el hallazgo que más imprimimos y, por sí solo,\nno te dice casi nada sobre si alguien puede llegar a tus datos."," Tratarlo como\nuna brecha significa o arreglarlo con prisa por delante de las cosas que de\nverdad deciden quién lee tu base de datos, o aprender que las líneas ámbar son\nruido, que es peor.",[10,22,23,24,29],{},"Entre el 12 y el 14 de agosto de 2026 pasamos las mismas nueve comprobaciones\nexternas sobre 30.998 apps en producción hechas con Lovable, Bolt, v0, Replit y\nBase44. De las apps de las que esta comprobación obtuvo respuesta, a 30.756 de\n30.981 les faltaba al menos una cabecera. Las cifras completas están en\n",[25,26,28],"a",{"href":27},"\u002Fresearch\u002Fvibe-coded-app-security-2026","nuestro informe de escaneo",".",[31,32,34],"h2",{"id":33},"es-un-problema-que-falten-cabeceras-de-seguridad","¿Es un problema que falten cabeceras de seguridad?",[10,36,37],{},"Es un hueco real y casi siempre la línea menos urgente de tu informe.",[10,39,40],{},"Una cabecera de seguridad es una instrucción corta que tu servidor adjunta a\ncada página que envía, dirigida al navegador de la persona que visita y no a la\npersona. No dejes que otra web meta esta página dentro de un marco. No adivines\nqué tipo de archivo es este. No pases mi dirección completa cuando alguien haga\nclic en un enlace hacia fuera. Son notas para un ayudante que hace lo que le\ndiga cualquier web.",[10,42,43],{},"El resto de tu informe va de cerraduras. Si Row Level Security está activado, si\nhay una clave secreta en tu código, si un bucket de almacenamiento lista su\ncontenido: eso decide quién puede llegar a tus datos siquiera. Las notas y las\ncerraduras se quieren las dos, y la nota que nunca escribiste no es por lo que\nla gente pierde una base de datos.",[10,45,46],{},"Nuestra calificación lo trata así. Una cabecera que falta resta cinco puntos\nsobre cien y no limita el techo, así que una app cuyo único hallazgo es este\nsale con 95 y una nota A.",[31,48,50],{"id":49},"qué-encontramos-en-30998-apps","Qué encontramos en 30.998 apps",[10,52,53],{},"Las cabeceras faltantes aparecieron casi en todas partes, y apenas se movieron\ncon el resto del informe.",[10,55,56],{},"25.821 de esas apps obtuvieron respuesta de las nueve comprobaciones, que es el\ngrupo donde \"no había nada más\" significa algo. De ellas, a 25.606 les faltaba\nal menos una cabecera y 215 tenían las cinco.",[58,59],"diagram",{"alt":60,"caption":61,"src":62},"Una cuadrícula con cuatro cifras. Las filas son el hallazgo de cabeceras, dibujado como una barra llena si está presente y una barra vacía discontinua si falta. Las columnas son el resto del informe, una marca para nada encontrado y una cruz para algo encontrado. Fila superior: 70 y 145. Fila inferior: 17.043 y 8.563.","Las apps a las que les faltaban cabeceras no tenían más probabilidad de tener algo más mal que las que tenían las cinco.","\u002Fblog\u002Fmissing-security-headers\u002Fdoes-it-predict-anything-1600x900.png",[10,64,65,66,69],{},"De las 25.606 apps a las que les faltaba al menos una cabecera, ",[17,67,68],{},"17.043 no\ntenían nada más mal",". Dos de cada tres. Era el único problema de su informe.",[10,71,72],{},"Ahora lee la otra fila, que es la parte que nos sorprendió. De las 215 apps que\ntenían las cinco cabeceras puestas, 145 tenían algo más mal. Esa es una tasa de\nproblemas reales más alta que entre las apps con cabeceras faltantes, no más\nbaja.",[10,74,75],{},"No medimos por qué, y la lectura honesta es estrecha: sea lo que sea lo que\nencontraron estos escaneos, el hallazgo de cabeceras no lo predijo. Una app con\nun juego perfecto de cabeceras no era una app más segura en nuestros datos. La\nexplicación más probable es que poner cabeceras siquiera implica que alguien\nconfiguró un hosting de verdad, lo que suele implicar una app más grande con más\ncosas que hacer mal, pero eso es una suposición y no la hemos comprobado.",[10,77,78,79,29],{},"Si quieres ver qué líneas de estas produce tu propia app, el escaneo es\ngratuito, tarda unos 20 segundos y no necesita cuenta:\n",[25,80,82],{"href":81},"\u002Fsecurity-scanner","escanea tu app",[31,84,86],{"id":85},"qué-hace-realmente-cada-cabecera","Qué hace realmente cada cabecera",[10,88,89],{},"Cada una apaga un comportamiento del navegador que viene activado de fábrica.",[91,92,93,109],"table",{},[94,95,96],"thead",{},[97,98,99,103,106],"tr",{},[100,101,102],"th",{},"Cabecera",[100,104,105],{},"Qué le dice al navegador",[100,107,108],{},"Qué permite su ausencia",[110,111,112,127,140,153,166],"tbody",{},[97,113,114,121,124],{},[115,116,117],"td",{},[118,119,120],"code",{},"Content-Security-Policy",[115,122,123],{},"Desde qué sitios puede esta página cargar código y estilos",[115,125,126],{},"Un script inyectado puede enviar datos a donde quiera",[97,128,129,134,137],{},[115,130,131],{},[118,132,133],{},"Strict-Transport-Security",[115,135,136],{},"Vuelve siempre por HTTPS, nunca por HTTP a secas",[115,138,139],{},"Una visita en una red no fiable puede ser empujada a HTTP a secas",[97,141,142,147,150],{},[115,143,144],{},[118,145,146],{},"X-Frame-Options",[115,148,149],{},"No dejes que otro sitio muestre esta página dentro de un marco",[115,151,152],{},"Tu página puede cargarse de forma invisible dentro de la de otra persona",[97,154,155,160,163],{},[115,156,157],{},[118,158,159],{},"X-Content-Type-Options",[115,161,162],{},"Fíate del tipo de archivo que te di y no lo adivines por el contenido",[115,164,165],{},"Un archivo que alguien subió puede servirse como un tipo de archivo distinto",[97,167,168,173,176],{},[115,169,170],{},[118,171,172],{},"Referrer-Policy",[115,174,175],{},"Cuánto de esta dirección pasar cuando alguien hace clic hacia fuera",[115,177,178],{},"URLs completas, con todo lo que lleven dentro, llegan a servidores ajenos",[10,180,181,182,184,185,188,189,191],{},"Dos de ellas se solapan, y el escáner lo tiene en cuenta. Una\n",[118,183,120],{}," que contenga ",[118,186,187],{},"frame-ancestors"," hace el mismo trabajo\nque ",[118,190,146],{},", así que nuestra comprobación cuenta cualquiera de las dos\ny no exige las dos.",[31,193,195],{"id":194},"cuándo-una-cabecera-que-falta-es-todo-el-problema","Cuándo una cabecera que falta es todo el problema",[10,197,198],{},"Cuando tu app tiene algo que merezca la pena pulsar mientras alguien tiene la\nsesión iniciada.",[10,200,201],{},"Ese es el caso del clickjacking, y es el único que funciona sin ningún otro\nerror. Alguien carga tu app en un marco invisible dentro de una página que\ncontrola y pone sus propios botones encima de los tuyos, de modo que quien ya\ntiene la sesión iniciada pulsa lo que parece su página y da en un control tuyo:\nel botón que borra una cuenta, aprueba una transferencia o cambia una dirección\nde correo.",[58,203],{"alt":204,"caption":205,"src":206},"Dos filas. En la primera, una página viaja hacia la derecha y una barra la detiene antes de llegar a un panel vacío y discontinuo. En la segunda no hay barra, y la página aparece dibujada pequeña dentro del otro panel, con un puntero del ratón sobre su botón.","Con la cabecera, el navegador se niega a dibujar tu página dentro de otro sitio. Sin ella, eso es algo perfectamente previsto.","\u002Fblog\u002Fmissing-security-headers\u002Floaded-inside-another-page-1600x790.png",[10,208,209],{},"La persona tiene la sesión iniciada, así que la acción lleva su sesión detrás.\nNo hace falta que nada de tu base de datos esté mal configurado. Lo que hace que\nfuncione es que al navegador nunca se le dijo que se negara.",[10,211,212,214],{},[118,213,172],{}," tiene una versión más pequeña de la misma forma. Si una página\ntuya con sesión iniciada lleva algo identificativo en la URL y enlaza hacia\nfuera a un servidor de imágenes o a un script de analítica, la dirección entera\nviaja con el clic. Quien gestione ese otro servidor ve dónde estaba tu usuario.",[10,216,217,218,220,221,223,224,226],{},"Las otras tres son condicionales. Importan cuando ya ha salido algo mal, y su\ntrabajo es que quede pequeño. Una ",[118,219,120],{}," limita lo que un\nscript inyectado puede hacer con su acceso. ",[118,222,159],{}," importa si\ndesconocidos pueden subirte archivos. ",[118,225,133],{}," cubre a quien\nusa tu app en una red que no controla.",[31,228,230],{"id":229},"necesito-cabeceras-de-seguridad","¿Necesito cabeceras de seguridad?",[10,232,233],{},"Sí. Son baratas, y van después de los hallazgos que deciden quién puede leer tu\nbase de datos.",[10,235,236],{},"El orden que se desprende de la medición de arriba: primero todo lo crítico o\nalto de tu informe, las cabeceras después. Si en tu informe solo está esta\nlínea, como les pasaba a 17.043 de las apps que escaneamos, entonces las\ncabeceras encabezan tu lista por defecto.",[10,238,239,240,243,244,247,248,251],{},"Dos de las cinco no cuestan nada. ",[118,241,242],{},"X-Content-Type-Options: nosniff"," y\n",[118,245,246],{},"Referrer-Policy: strict-origin-when-cross-origin"," son una línea cada una, no\ntienen un valor equivocado que elegir y no pueden romper una app que funciona.\n",[118,249,250],{},"X-Frame-Options: DENY"," también es una línea, y conviene mirarla antes si\nincrustas tu propia app en algún sitio a propósito.",[10,253,254,256,257,260],{},[118,255,120],{}," es la que da trabajo de verdad. Un primer intento\nsuele bloquear algo que tu propia página necesitaba, y el síntoma es una función\nque deja de funcionar sin avisar. Publícala como\n",[118,258,259],{},"Content-Security-Policy-Report-Only",", que te dice qué habría bloqueado sin\nbloquear nada, y lee los informes de una semana antes de activarla.",[31,262,264],{"id":263},"cómo-añadirlas","Cómo añadirlas",[10,266,267],{},"En lo que de verdad sirve tu app a internet, que muchas veces no es el sitio\ndonde la construyes.",[10,269,270,271,274,275,278,279,282],{},"La mayoría de los builders despliegan en un hosting que es dueño de la\nrespuesta, así que el ajuste vive allí. En Vercel es ",[118,272,273],{},"headers"," dentro de\n",[118,276,277],{},"vercel.json",". En Netlify y Cloudflare Pages es un archivo ",[118,280,281],{},"_headers"," en la raíz\nde lo que publicas. Detrás del proxy de Cloudflare es una Transform Rule. Si\ntienes tu propio servidor, es tu configuración de nginx o de Caddy.",[284,285,287],"callout",{"type":286},"warn",[10,288,289,292],{},[17,290,291],{},"Si tu app está en el subdominio propio de tu builder, puede que no puedas\nponerlas en absoluto."," La plataforma envía la respuesta, las cabeceras son\ndecisión suya, y no hay ningún archivo que puedas añadir que las sobrescriba.\nEsa es una respuesta real, no que no hayas buscado bastante. Conectar un dominio\npropio es lo que te da un hosting tuyo que configurar y, mientras no quieras\nuno, este hallazgo puede quedarse tranquilamente en tu informe.",[10,294,295],{},"Lo que hay que saber de las cabeceras una vez puestas es que se caen sin que\nnadie las toque. Mudarte a un dominio propio, poner un proxy delante, cambiar de\nhosting, tocar la configuración del framework: las cabeceras que añadiste viven\nen uno de esos sitios, y cualquiera de esos movimientos puede dejarlas atrás.\nNada te avisa. La página sigue funcionando y el ajuste ya no está.",[10,297,298,299,303,304,29],{},"Para eso está ",[25,300,302],{"href":301},"\u002F#pricing","Reeve Monitor",". Vuelve a pasar la comprobación\ncompleta cada hora en hasta tres apps, vigila la disponibilidad cada 60 segundos\ny te avisa cuando cambia un resultado, en vez de esperar a que mires. Monitor\nvigila y nada más, así que si además quieres una copia de tu base de datos en un\nsitio al que tu builder no llegue,\n",[25,305,307],{"href":306},"\u002Fsupabase-backups","eso es Care, y cubre Supabase",[31,309,311],{"id":310},"qué-hacer-ahora-mismo","Qué hacer ahora mismo",[313,314,315],"key-takeaways",{},[316,317,318,322,331,337,343,346],"ul",{},[319,320,321],"li",{},"Lee primero el resto de tu informe. Si hay algo marcado como crítico o alto, ese es el trabajo, y las cabeceras esperan.",[319,323,324,325,327,328,330],{},"Pon hoy ",[118,326,242],{}," y ",[118,329,246],{},". Una línea cada una, nada que decidir, nada que romper.",[319,332,333,334,336],{},"Pon ",[118,335,250],{}," si la gente inicia sesión en tu app y puede hacer algo importante con un solo clic.",[319,338,339,340,342],{},"Deja ",[118,341,120],{}," para el final y arráncala en modo report-only, para enterarte tú antes que tus visitantes de lo que rompe.",[319,344,345],{},"Si estás en un subdominio de builder sin ajuste de cabeceras, deja el hallazgo en paz. Todavía no es tuyo.",[319,347,348],{},"Vuelve a comprobarlas después de cambiar de dominio, poner un proxy o mudarte de hosting. Es cuando desaparecen.",[10,350,351,352,356,357,361],{},"Las cabeceras merecen una tarde tranquila una vez que el resto del informe está\nlimpio. Si prefieres recorrer la lista entera en orden, la\n",[25,353,355],{"href":354},"\u002Fchecklist","lista de seguridad de 10 minutos"," cubre qué apagar en una app recién\nlanzada, y\n",[25,358,360],{"href":359},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","los hallazgos que sí deciden quién lee tu base de datos","\nson los primeros que hay que quitar de en medio.",{"title":363,"searchDepth":364,"depth":364,"links":365},"",3,[366,368,369,370,371,372,373],{"id":33,"depth":367,"text":34},2,{"id":49,"depth":367,"text":50},{"id":85,"depth":367,"text":86},{"id":194,"depth":367,"text":195},{"id":229,"depth":367,"text":230},{"id":263,"depth":367,"text":264},{"id":310,"depth":367,"text":311},"Fundamentos de seguridad","\u002Fblog\u002Fmissing-security-headers\u002Fcover-1200x630.png","La lista de cabeceras que un sitio devuelve con cada página, con cuatro de sus filas rayadas y vacías donde iría un valor.","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.",false,"md",[381,384,387,390,393],{"q":382,"a":383},"Mi escaneo dice que faltan cabeceras de seguridad. ¿Me han hackeado la app?","No. Una cabecera que falta es un ajuste que nunca se activó, y no es prueba de que haya ocurrido nada. En el hallazgo no interviene nadie que haya llegado a tus datos ni a tu cuenta. Describe una instrucción que tu sitio podría estar dando a los navegadores que lo visitan y ahora mismo no da.",{"q":385,"a":386},"¿Qué cabecera de seguridad debería poner primero?","X-Content-Type-Options y Referrer-Policy, porque ambas son una sola línea, ninguna tiene un valor equivocado que elegir y ninguna puede romper una app que funciona. Después X-Frame-Options, si la gente inicia sesión en tu app. Después Strict-Transport-Security. Content-Security-Policy la última, porque es la única de las cinco que exige pensar de verdad y la única que puede impedir que se ejecuten tus propios scripts.",{"q":388,"a":389},"Estoy en el dominio por defecto de mi builder y no hay ningún ajuste para cabeceras. ¿Ahora qué?","Déjalas. Cuando tu app se sirve desde un subdominio de la plataforma, las cabeceras de respuesta son decisión de la plataforma y no tuya, y no hay ningún archivo que puedas añadir que las cambie. Conecta un dominio propio si quieres controlar esto, porque el dominio es lo que te deja poner tu propio hosting o un proxy delante de la app. Hasta entonces, dedica el esfuerzo a los hallazgos que sí te toca arreglar.",{"q":391,"a":392},"¿Puede una Content-Security-Policy romper mi app?","Sí, y ese es el resultado normal de un primer intento. Una política que no permite scripts en línea detendrá los scripts en línea, incluidos los que generó tu builder, y la página se queda en blanco o pierde una función, con un error que solo aparece en la consola del navegador. Empieza con Content-Security-Policy-Report-Only, que informa de lo que habría bloqueado y no bloquea nada, y lee los informes durante una semana antes de activarla de verdad.",{"q":394,"a":395},"¿Ayudan las cabeceras de seguridad si mi base de datos la puede leer cualquiera?","No. Las cabeceras son instrucciones para los navegadores que visitan tu sitio, y quien lee tu base de datos directamente no está usando un navegador ni visitando tu sitio. Esa petición va directa a tu proveedor de base de datos y no toca tus páginas nunca, así que ninguna cabecera puesta en ellas se le aplica. Eso lo decide Row Level Security.","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",[398,399,400,401,402,403,404],"faltan cabeceras de seguridad","falta content-security-policy","falta x-frame-options","necesito cabeceras de seguridad","comprobar cabeceras de seguridad","falta strict-transport-security","es un problema que falten cabeceras de seguridad",{},true,"Faltan cabeceras de seguridad: ¿cuándo importa?","\u002Fblog\u002Fmissing-security-headers","2026-09-04",{"title":5,"description":377},"blog\u002Fmissing-security-headers",[413,414,415,416],"Que falten cabeceras de seguridad es el hallazgo más común que existe y, por sí solo, dice casi nada sobre si alguien puede llegar a tus datos.","Escaneamos 30.998 apps en producción. Dos de cada tres de las que tenían cabeceras faltantes no tenían nada más mal.","Aun así vale la pena arreglarlo, y va después de las cosas que deciden quién puede leer tu base de datos.","En algunos dominios de builders no puedes ponerlas tú, y dejarlas así es una respuesta razonable.","SZ2nWb-lYQ38qu8XwzJLGPWNh29u8Frl0_FxUnpwrkM",[419,426,432,438,444,450,456,462,468,474,480,486,492,498,504,510,516,522,528,534,535,541,547,553,559,565,571,577,583,589,595,601,607,613,619,624,629,635,641,647,652,658],{"path":420,"title":421,"description":422,"published":423,"category":424,"image":425,"draft":378},"\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","Backups","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":427,"title":428,"description":429,"published":430,"category":374,"image":431,"draft":378},"\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":433,"title":434,"description":435,"published":436,"category":374,"image":437,"draft":378},"\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":439,"title":440,"description":441,"published":442,"category":374,"image":443,"draft":378},"\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":445,"title":446,"description":447,"published":448,"category":374,"image":449,"draft":378},"\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":451,"title":452,"description":453,"published":454,"category":374,"image":455,"draft":378},"\u002Fblog\u002Fvite-and-next-public-env-vars","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":457,"title":458,"description":459,"published":460,"category":374,"image":461,"draft":378},"\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":463,"title":464,"description":465,"published":466,"category":374,"image":467,"draft":378},"\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":469,"title":470,"description":471,"published":472,"category":374,"image":473,"draft":378},"\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":475,"title":476,"description":477,"published":478,"category":424,"image":479,"draft":378},"\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":481,"title":482,"description":483,"published":484,"category":424,"image":485,"draft":378},"\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":487,"title":488,"description":489,"published":490,"category":424,"image":491,"draft":378},"\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":493,"title":494,"description":495,"published":496,"category":374,"image":497,"draft":378},"\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":499,"title":500,"description":501,"published":502,"category":374,"image":503,"draft":378},"\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":505,"title":506,"description":507,"published":508,"category":374,"image":509,"draft":378},"\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":511,"title":512,"description":513,"published":514,"category":374,"image":515,"draft":378},"\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":517,"title":518,"description":519,"published":520,"category":374,"image":521,"draft":378},"\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":523,"title":524,"description":525,"published":526,"category":374,"image":527,"draft":378},"\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":529,"title":530,"description":531,"published":532,"category":374,"image":533,"draft":378},"\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":408,"title":5,"description":377,"published":409,"category":374,"image":396,"draft":378},{"path":536,"title":537,"description":538,"published":539,"category":374,"image":540,"draft":378},"\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":542,"title":543,"description":544,"published":545,"category":374,"image":546,"draft":378},"\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":548,"title":549,"description":550,"published":551,"category":424,"image":552,"draft":378},"\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":554,"title":555,"description":556,"published":557,"category":374,"image":558,"draft":378},"\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":560,"title":561,"description":562,"published":563,"category":424,"image":564,"draft":378},"\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":566,"title":567,"description":568,"published":569,"category":374,"image":570,"draft":378},"\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":572,"title":573,"description":574,"published":575,"category":374,"image":576,"draft":378},"\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":578,"title":579,"description":580,"published":581,"category":374,"image":582,"draft":378},"\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":584,"title":585,"description":586,"published":587,"category":374,"image":588,"draft":378},"\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":590,"title":591,"description":592,"published":593,"category":424,"image":594,"draft":378},"\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":596,"title":597,"description":598,"published":599,"category":424,"image":600,"draft":378},"\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":602,"title":603,"description":604,"published":605,"category":374,"image":606,"draft":378},"\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":608,"title":609,"description":610,"published":611,"category":374,"image":612,"draft":378},"\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":614,"title":615,"description":616,"published":617,"category":424,"image":618,"draft":378},"\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":359,"title":620,"description":621,"published":622,"category":374,"image":623,"draft":378},"¿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":625,"title":626,"description":627,"published":622,"category":374,"image":628,"draft":378},"\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":630,"title":631,"description":632,"published":633,"category":374,"image":634,"draft":378},"\u002Fblog\u002Fsupabase-new-api-keys","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":636,"title":637,"description":638,"published":639,"category":424,"image":640,"draft":378},"\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":642,"title":643,"description":644,"published":645,"category":374,"image":646,"draft":378},"\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":648,"title":649,"description":650,"published":645,"category":424,"image":651,"draft":378},"\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":653,"title":654,"description":655,"published":656,"category":424,"image":657,"draft":378},"\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":659,"title":660,"description":661,"published":656,"category":374,"image":662,"draft":378},"\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",1790150954109]