Saltar al contenido
Seguridad

Solo lectura, nunca clonado,
y ningún token en la base de datos.

Cada afirmación de esta página nombra el mecanismo que la sostiene, porque tu equipo de seguridad lo preguntará. La última sección es la que no tiene mecanismo — lo que no hemos hecho, con el mismo tamaño de letra que lo que sí.
Acceso al repository
Solo lectura
Repositories clonados
Ninguno, nunca
Tokens en la base de datos
Ninguno de GitHub
Markdown saneado
Antes de guardarlo
Material de clave guardado
Solo SHA-256
Credenciales

Tres clases, y qué pasa con cada una

La regla que hay debajo de todas: guardamos la forma menos duradera de una credencial que aún funcione y, cuando tenemos que guardar una, decimos dónde y bajo qué clave.

GitHub

Una GitHub App, de solo lectura, sobre los repositories que elijas.

  • Revocable desde GitHub en cualquier momento, sin preguntarnos.
  • Los tokens de instalación se emiten bajo demanda a partir de la clave privada de la App y se guardan en memoria durante su hora. Nada con forma de token se escribe nunca en la base de datos.
  • La clave privada es el único secreto de larga duración y su sitio es un almacén de secretos, no junto a los datos.
  • Conectar un repository pregunta a GitHub como tú, no como la instalación — así nadie puede conectar un repository que no pueda leer personalmente.

GitLab

Un token de acceso de proyecto o de grupo que pegas, cifrado en reposo.

  • Cifrado con su propia clave, a propósito distinta del secreto de sesión: rotar el secreto de sesión cierra la sesión de todos y es rutina; rotar esta implica volver a cifrar cada credencial.
  • Un token con permiso de escritura se rechaza al conectar, indicando cuál.
  • Un token sin caducidad se rechaza de entrada.
  • La consecuencia se dice en vez de esquivarla: como no guardamos un token con permiso de escritura, no podemos crear webhooks de GitLab, y la actualización depende en su lugar de un sondeo periódico.

Claves de API

Para agentes y CI. De la organización, no tuyas.

  • Solo se guarda un SHA-256 de la clave. El valor se muestra una vez, al emitirla, y no hay forma de recuperarlo — porque esa forma significaría que se guardó en algún sitio.
  • Una clave pertenece a la organización y no a su autor, así que un trabajo de CI no se rompe el día en que esa persona cambia de equipo.
  • Una clave nombra exactamente un proyecto. Ya no se puede emitir una clave para toda la organización.
  • La revocación surte efecto en la siguiente petición. Nada guarda la consulta en caché.
Renderizado

El Markdown permite HTML en crudo, y ese es el riesgo más grave en un producto como este

Una etiqueta <script> en el README de alguien se ejecutaría si no en nuestro origen, con la sesión del lector. Cada documento se sanea en el servidor según una lista permitida antes de guardarse como HTML — no se filtra al renderizar, donde una sola ruta que lo olvide es una ruta que entrega un exploit.

El Markdown en bruto sigue siendo la fuente de verdad. El HTML renderizado es solo una caché, indexada por el hash del contenido y una versión del renderizador, así que endurecer el renderizador lo invalida todo de una vez y no hay nada que migrar.

Tu código

El repository nunca se clona, y nunca se descarga nada fuera de tu documentación

Una sola llamada a la API devuelve la estructura de carpetas más un hash de contenido por archivo. No hay binario de git, ni copia de trabajo, ni nada escrito en disco. Solo se descargan blobs Markdown, y solo dentro de la raíz de la documentación — un archivo fuente es un nombre que podemos ver en una ruta, nunca un contenido que descargamos.

Las imágenes de un repository privado se sirven a través de un proxy autenticado en lugar de enlazarse directamente, así que cargan para quienes pueden verlas y para nadie más.

Iniciar sesión

Las cookies de sesión van cifradas, no solo firmadas

Una sesión OAuth lleva el token de GitHub del usuario, así que una cookie solo firmada sería legible. Las cookies se cifran; las contraseñas se procesan con Argon2 detrás de un puerto, nunca con una biblioteca cuya dependencia retiró Python.

La revocación es real y no nominal. Cada petición autenticada compara una época en la fila de la cuenta, que es el precio honesto de retirar una credencial que lleva su propia validez — una cookie descifrada no es una cookie autenticada. Cerrar sesión en todos los dispositivos es una sola acción, y desconectar GitHub invalida las sesiones que llevaban su token en lugar de dejarlas funcionando hasta que caduquen.

Hay una lista de sesiones: una etiqueta de plataforma aproximada y una dirección truncada a un /24. Sin ciudad, sin país y sin suposiciones sobre si un inicio de sesión fue inusual — eso exige una base de geolocalización o un modelo de lo habitual, e inventar cualquiera de los dos es como una lista de dispositivos empieza a informar de incidentes que nunca ocurrieron.

Acceso

Nada es legible por defecto, y el navegador nunca decide

Unirse a una organización no da acceso a ningún documento. Un miembro lee un proyecto mediante un acceso de equipo o uno directo; alguien sin equipo ni acceso no lee nada en absoluto. No hay ningún ajuste de visibilidad que dé acceso a todos en silencio.

El acceso se resuelve en el servidor, en la única consulta por la que ya pasa cada ruta de lectura. Un repository al que perdiste el acceso responde 404 — igual que uno que nunca existió, así que la respuesta no sirve para averiguar qué existe.

No se compara ningún rol en TypeScript. Incluso las respuestas fila a fila de «¿se puede quitar a esta persona?» que muestra la pantalla de miembros se calculan en el servidor, así que ninguna copia de la jerarquía llega al cliente para desviarse.

Red

Una URL que tú aportas se trata como una superficie de ataque

Un host de GitLab autogestionado es una URL que un cliente escribe y que el servidor luego consulta, lo que es una primitiva SSRF. Las comprobaciones son predicados puros: solo https, cada dirección resuelta contrastada con los rangos privados, de loopback, link-local y reservados, y las redirecciones rechazadas de entrada en lugar de seguirlas y volver a comprobarlas.

El orden de un webhook es fijo y nunca se reorganiza: cuerpo en bruto, luego la firma comparada en tiempo constante, luego el análisis. Leer un payload antes de verificarlo es analizar algo que envió un desconocido.

La dirección del cliente es configuración, no una cabecera. Por defecto, las cabeceras reenviadas se ignoran por completo; donde se cuentan los proxies, la dirección se toma del extremo que quien llama no puede ampliar añadiendo valores delante.

Agentes

Una credencial de máquina es más estrecha que la persona que la creó, a propósito

Una clave puede llevar un estado de revisión mínimo, y los documentos por debajo responden 404 en todas las puertas — incluidas las rutas de lectura, porque un umbral que se detiene en una superficie es un umbral con una segunda puerta de entrada. Vive en la credencial y no en un argumento de herramienta: un filtro que pasa el agente es un filtro que un prompt puede convencerle de no pasar.

Ninguna herramienta de esa superficie modifica un documento del repository, cierra la nota de un revisor, borra un artifact ni hace a un modelo una pregunta libre. Son ausencias, no ajustes — no hay ninguna opción que un administrador pueda conceder, y esa es la idea.

Tu contenido

El texto de los documentos solo sale de la máquina para una organización que lo ha pedido

Es la única vía de salida que lleva contenido del cliente, y el interruptor está desactivado por defecto — activarlo por defecto habría hecho que cada organización existente enviara documentos a un tercero solo porque hubo un despliegue. Activarlo queda escrito en el registro de auditoría.

Un documento vacío no hace ninguna llamada: pedirle a un modelo que no invente es una petición, mientras que no llamarlo es una garantía. Un proveedor nombrado sin su clave se niega en lugar de devolver texto de relleno, porque un resumen inventado guardado contra contenido real se sirve como real hasta que ese contenido cambia.

Pruebas

Una fila de auditoría se escribe dentro de la misma transacción que el cambio

Nunca después del commit, nunca en la medida de lo posible, nunca desde un trabajo en segundo plano. Si el cambio se revierte, el registro se va con él, y si el registro no se puede escribir, el cambio no se aplica. El nombre del autor y la etiqueta del sujeto se copian en la fila, porque un equipo borrado tiene que seguir leyéndose como el equipo que fue.

El registro se puede filtrar y exportar, y se conserva durante el periodo que fija tu plan. Nada puede borrar una sola fila — quien pueda quitar una fila puede quitar la que importa.

Tus controles

Lo que manejas tú

Dos de estos dependen del plan y la página dice cuáles, porque enterarse justo cuando hace falta es tarde.

Lista de direcciones permitidas

Business y Enterprise

Rechaza toda petición que venga de una dirección que no hayas indicado. Alcanza a las claves de API igual que a los navegadores — una credencial de máquina se comprueba en la puerta antes de atender la petición.

Inicio de sesión con GitHub obligatorio

Enterprise

Retira los documentos a quien no tenga identidad de GitHub, para que el acceso siga una cuenta que tu organización puede ver.

Política de sesión

Todos los planes

Define cuánto dura una sesión, y cierra la sesión de todos los miembros a la vez cuando haga falta.

Retención de la auditoría

Todos los planes

Elige cuánto tiempo se conserva el registro. Un periodo más largo es la ventaja; la purga sigue un calendario, no se lanza a demanda.

Con honestidad

Lo que no hemos hecho

Una página de seguridad sin ninguna laguna es una página de seguridad que nadie se cree. Estas son reales.

SSO y SAML no están construidos
La tarjeta existe en los ajustes de seguridad de la organización y es marcado estático. Forma parte de lo que cubre un acuerdo Enterprise y no es algo que puedas activar hoy. Preferimos decirlo aquí antes que dejar que lo descubras después de firmar.
Sin SOC 2, sin ISO 27001, sin prueba de penetración
No se ha hecho ninguna. Si tu proceso de compras exige una, todavía no estamos listos para ti, y esa es una respuesta real, no una promesa de hoja de ruta.
El DNS rebinding está cerrado; la fijación de conexión no
Las comprobaciones de dirección se hacen al resolver. Un host que responde distinto en la segunda consulta está cubierto, pero no fijamos la conexión a la dirección que validamos.
Sin claves gestionadas por el cliente en un despliegue que operamos
Las claves de cifrado pertenecen al despliegue. Tener las tuyas implica operar el tuyo: una instalación dentro de tu red es una condición Enterprise, y en el despliegue que operamos las claves siguen siendo nuestras.

¿Has encontrado algo mal en todo esto? [email protected]. Preferimos saberlo por ti que leerlo en otro sitio.

Dale acceso de lectura a un repository y retíraselo con un clic.

La prueba más pequeña posible de todo esto es un repository público y cinco minutos.

Empezar gratis