Reports
MEDIA[LÓGICA DE NEGOCIO]#3591764

Lovable: invitar con rol de solo lectura sin plan Pro cambiando un parámetro de la petición

La API de Lovable no comprobaba el plan al crear enlaces de invitación: con una cuenta gratuita bastaba cambiar access_level de write a read para conceder "View access", una opción reservada al plan Pro.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

En Lovable, el propietario de un proyecto puede compartirlo mediante un enlace de invitación. La interfaz solo deja poner ese enlace en "View access" (solo lectura) si la cuenta tiene el plan Pro; con el plan gratuito hay que quedarse en "Edit access".

Esa restricción no se aplicaba en el servidor. El endpoint que genera el enlace, POST /projects/<ID>/magic-codes en api.lovable.dev, aceptaba el valor read en el parámetro access_level sin comprobar la suscripción. Interceptando la petición y cambiando ese valor, una cuenta gratuita obtenía un enlace de invitación con rol de lector que funcionaba de verdad: la persona invitada entraba al proyecto con permiso viewer.

El programa (lovable-vdp) lo clasificó con severidad media y lo dio por resuelto. El reporte se envió el 8 de marzo de 2026 y se divulgó el 16 de marzo de 2026.

Pasos de reproducción

Hacen falta dos cuentas: la del propietario del proyecto (en plan gratuito) y la de quien recibirá la invitación, además de un proxy de interceptación para modificar las peticiones.

  1. Con la cuenta del propietario, crea un proyecto: elige cualquier plantilla, pulsa el botón para usarla, ponle nombre y pulsa Remix.
  2. Abre el proyecto creado desde la sección Projects.
  3. Pulsa share, arriba a la derecha. En el enlace de invitación se indica que hace falta el plan Pro para cambiar el acceso a View access.
  4. En el enlace de invitación, pulsa Disabled.
  5. Con la interceptación activada, vuelve a poner el acceso en Edit access.
  6. Primero sale una petición OPTIONS al endpoint de proyectos: déjala pasar y espera a la petición POST.
  7. En esa petición POST, cambia el parámetro access_level de write a read e intercepta también la respuesta. Ejemplo de la petición ya modificada, tal como aparece en el reporte:
POST /projects/Project-ID/magic-codes HTTP/2
Host: api.lovable.dev
Cookie: [Your-Cookie]
User-Agent: []
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://lovable.dev/
Authorization: Bearer [Your-Authorization-Header]
Content-Type: application/json
Content-Length: 23
Origin: https://lovable.dev
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Priority: u=0
Te: trailers

{"access_level":"read"}

El único cambio respecto a la petición original es el cuerpo:

-{"access_level":"write"}
+{"access_level":"read"}
  1. La respuesta refleja el permiso read sin ningún error.
  2. Vuelve al proyecto y recarga la página. Al pulsar share, el enlace aparece ahora con View access, aunque la cuenta sigue en el plan gratuito.
  3. Copia el enlace de invitación, ábrelo con la segunda cuenta y acepta la invitación al proyecto.
  4. En share → people you invited se ve que la segunda cuenta ha entrado con el permiso viewer.

Impacto

  • Un usuario del plan gratuito puede usar una función que Lovable reserva a los suscriptores Pro (invitar con rol de solo lectura) sin pagar por ella.
  • Para la plataforma supone un uso no autorizado de funcionalidad de pago y un posible perjuicio económico al saltarse la suscripción.
  • Desde el punto de vista de la seguridad, afecta sobre todo a la integridad de las reglas de negocio: el sistema no validaba qué permisos podía asignar cada usuario según su plan.

Qué aprender de este caso

  • Si una opción aparece bloqueada en la interfaz "por plan", prueba a mandarla igualmente: aquí bastaba con cambiar write por read en el cuerpo de la petición que crea el enlace de invitación.
  • Los endpoints que generan invitaciones, enlaces mágicos o enlaces compartidos son buen sitio donde buscar: suelen recibir el rol o nivel de acceso como parámetro, y es fácil que el servidor no compruebe si quien lo pide tiene derecho a concederlo.
  • Al programar, la comprobación de suscripción tiene que hacerse en el servidor, en el mismo endpoint que recibe access_level, comparando el valor pedido con los roles que permite el plan del usuario, y no solo deshabilitando la opción en el selector.
  • Conviene repetir esa comprobación al aceptar la invitación: así un enlace generado de forma indebida, o antes de un cambio de plan, no concede permisos de pago.