CodeQL en GitHub Advanced Security: qué cubre de verdad
Actualizado: 2026-05-03
CodeQL es el motor de análisis semántico de código de GitHub, heredero de Semmle, y desde hace tres años el corazón de la oferta GitHub Advanced Security. Con el soporte para Rust llegado en vista previa a finales de 2024 y la mejora continua de las bibliotecas de queries, CodeQL cubre hoy casi todos los lenguajes que usa una empresa media. La pregunta que merece respuesta honesta es qué detecta de verdad, qué no detecta y cómo integrarlo para que el equipo lo aproveche en vez de ignorarlo.
Este texto es un balance desde el uso en varias bases de código: dónde funciona bien, dónde aparecen falsos positivos repetidos, qué tipo de vulnerabilidades se escapan y qué hábitos de revisión lo hacen útil. Conviene leerlo junto con el análisis de Semgrep como SAST complementario para tener una visión completa del panorama.
Puntos clave
- CodeQL trata el código como dato consultable: detecta flujos de datos reales, no solo patrones léxicos.
- Java, C# y JavaScript son los más maduros; Rust todavía en vista previa con catálogo reducido.
- Brilla en inyecciones, XSS, deserialización insegura y criptografía mal configurada.
- No detecta lógica de negocio, condiciones de carrera ni dependencias vulnerables.
- Tres decisiones marcan la diferencia: afinar el conjunto de queries, integrar en PR y escribir queries propias.
Cómo funciona por debajo
CodeQL trata el código como un dato consultable. El compilador extrae una base de datos que representa el código fuente: tablas de funciones, llamadas, tipos, flujo de control y flujo de datos. Sobre esa base se ejecutan queries escritas en un lenguaje declarativo que se parece a SQL con lógica recursiva.
Esta arquitectura es la diferencia esencial con los SAST clásicos basados en regex o AST simple:
- Un regex grep detecta «aquí llaman a
eval». - CodeQL detecta «este
evalconsume un valor que originalmente venía del parámetrousernamedel endpoint POST, sin haber pasado por la funciónsanitizeque el proyecto considera segura».
La segunda detección refleja riesgo real, no riesgo potencial genérico. El proceso tiene dos costes: la extracción de la base de datos (requiere compilar el proyecto entero, desde minutos hasta una hora en repos grandes) y la ejecución de las queries (relativamente barata una vez construida la base).
Los lenguajes y qué tan maduros son
La lista actual con soporte incluye:
- C, C++, C#, Go, Java, JavaScript/TypeScript, Python, Ruby, Swift y Rust (vista previa).
No todos tienen la misma madurez. Java, C# y JavaScript son los más pulidos, con bibliotecas de queries extensas y detección fina de vulnerabilidades típicas de esos ecosistemas. Python y Go están sólidos. Ruby y Swift tienen cobertura buena pero con menos queries para frameworks populares. Rust está en vista previa con catálogo todavía reducido.
La calidad de la detección depende tanto del lenguaje como del framework. CodeQL detecta inyección SQL muy bien en Spring Java o Express JavaScript; la detecta peor en un proyecto que usa un ORM propio o una capa de acceso a datos poco común, porque la biblioteca no tiene modelado ese flujo.
Lenguajes que CodeQL no cubre y que siguen siendo habituales en 2025:
- Kotlin (soporte alfa comunitario).
- Scala, PHP, Elixir, Dart.
Si tu stack pasa por estos, CodeQL no será la pieza principal de cobertura y habrá que complementar con herramientas específicas del lenguaje.
Qué detecta bien
Las categorías donde CodeQL destaca:
- Inyecciones (SQL, comandos, LDAP, NoSQL, XPath) donde hay origen claro y sumidero claro con flujo no demasiado convoluto.
- XSS reflejado y almacenado en aplicaciones web con framework reconocido.
- Deserialización insegura en Java y C#, especialmente con cadenas conocidas de gadgets.
- Desbordamiento y use-after-free en C y C++, aunque con tasa de falsos positivos más alta que en lenguajes manejados.
- Mala configuración de criptografía: algoritmos débiles, claves hardcodeadas, generación insegura de valores aleatorios.
- Patrones de contenedor y nube: exposición de secretos en entornos, permisos excesivos.
Un punto fuerte que se aprecia con el tiempo es la extensibilidad. CodeQL permite escribir queries propias en el mismo lenguaje declarativo. Si tu empresa tiene una función auditLog propia que debería invocarse en todos los endpoints que modifican datos, se puede escribir una query que detecte endpoints modificadores sin esa llamada. Aquí CodeQL se diferencia más de herramientas que solo ofrecen reglas predefinidas.
Qué se le escapa
No todo es detectable con análisis estático. Lo que se le escapa con más frecuencia:
- Problemas de lógica de negocio: IDOR, rupturas de autorización, errores en el modelo de amenazas. Siguen siendo trabajo humano o de análisis dinámico.
- Vulnerabilidades runtime-dependientes: condiciones de carrera reales en concurrencia compleja, problemas que solo emergen bajo carga, fallos provocados por servicios externos específicos.
- Cadenas de dependencias: una librería vulnerable en
package.jsonla detecta Dependabot (también parte de GHAS), no CodeQL. - Frameworks poco modelados: si usas Next.js con app router o SvelteKit, algunos flujos entre server y client components no están bien representados y los análisis de flujo de datos se interrumpen.
Cómo integrarlo para que sirva
Lo fácil es activar CodeQL con el workflow por defecto y olvidarse. Lo útil es incorporarlo de forma que el equipo lo aprecie en vez de ignorarlo. Tres decisiones marcan la diferencia:
Primera, afinar el conjunto de queries. Por defecto se ejecutan las queries de seguridad y de calidad. En una base de código sucia, las de calidad generan tanto ruido que tapan las de seguridad. La recomendación es arrancar solo con security-extended, arreglar el flujo hasta que aparezcan alertas limpias y después añadir calidad como segunda capa.
Segunda, integrar con la revisión de pull requests. CodeQL puede ejecutarse tanto en pushes a la rama principal como en PRs, comentando inline los hallazgos nuevos que introduce un cambio. El desarrollador ve el aviso en el contexto de su cambio, no en una consola de seguridad que nadie visita.
Tercera, invertir en queries propias para lo que importa en tu contexto. Las queries por defecto cubren vulnerabilidades comunes, pero las convenciones internas son específicas de cada empresa. Dedicar un día cada trimestre a escribir una o dos queries propias produce una batería que convierte CodeQL en parte del estilo del equipo. Complementa bien esta práctica con la estrategia de Semgrep para patrones más ligeros.
Costes operativos
GitHub Advanced Security se factura por committer activo en repositorios privados que lo tienen activado. En organizaciones medianas puede acumularse rápidamente y conviene modelarlo antes de activarlo de forma general. Para repositorios públicos, CodeQL es gratuito.
El coste menos visible es el de los minutos de CI. En un repositorio grande con varios lenguajes, la extracción de bases de datos puede consumir decenas de minutos por corrida. Se gestiona bien con:
- Cachés de extracción.
- Ejecución solo en ciertos eventos (no en cada push de cada rama).
- División del análisis por lenguaje para paralelizar.
El último coste es humano: alguien tiene que mirar las alertas, filtrar falsos positivos, mantener las queries propias actualizadas y decidir cuándo rechazar un PR por razones de seguridad. Sin esa figura, la herramienta genera deuda en vez de valor.
Cuándo compensa
CodeQL dentro de GHAS compensa cuando se cumplen varias condiciones: tu stack está entre los bien soportados; tienes equipo con capacidad de atender las alertas generadas; tu modelo de amenazas incluye vulnerabilidades estáticamente detectables como riesgo relevante; y estás dispuesto a invertir en queries propias para que la herramienta se adapte a tus convenciones, no al revés.
Si solo puedes permitirte una herramienta de seguridad en tu pipeline y trabajas sobre GitHub, CodeQL es muy probablemente la mejor primera inversión, por su integración y su cobertura. Si ya tienes un SAST maduro de otro proveedor, la decisión se complica: conviene pilotar CodeQL en paralelo durante un trimestre y comparar sobre el mismo código antes de decidir. Más allá del motor, lo que distingue una integración útil de una inútil es el hábito de revisión: sin ese hábito, cualquier SAST es solo ruido con presupuesto.