TL;DR
Los modelos de razonamiento no son necesarios para la mayoría de SAST , pero en casos extremos como el recorrido de rutas en JavaScript, detectan el doble de falsos positivos.
¿Son los modelos de razonamiento solo una moda pasajera?
Los «modelos de razonamiento» están viviendo un gran momento. Los grandes laboratorios de IA están inmersos en una batalla por el liderazgo, superando los límites del tamaño y el rendimiento de los modelos mediante leyes de escalado, un preentrenamiento más inteligente y un ajuste fino con RLHF (aprendizaje por refuerzo a partir de la retroalimentación humana). También están incorporando cadenas de pensamiento para que los modelos «piensen en voz alta» durante la inferencia. Esto les permite dominar sobre los sistemas que no son de IA en tareas lógicas y, de paso, encabezar las clasificaciones.
Es impresionante. Pero, ¿son realmente útiles en la práctica? Depende.
En el caso de AutoTriage*, mucho depende de la complejidad de la regla SAST.
*Resumen rápido: AutoTriage es una función que utiliza Aikido para filtrar los falsos positivos de SAST .
**SAST es una vulnerabilidad potencial descubierta en el código fuente, según lo informado por un detector de patrones codificado.
Demasiado caro para la mayoría de SAST
AutoTriage funciona en dos pasos: primero intentamos descartar la posibilidad de explotabilidad. Si eso es posible, podemos filtrar los falsos positivos. Esto requiere un pensamiento binario sobre la accesibilidad de las variables controladas por el usuario a las vulnerabilidades. Básicamente, el modelo comprueba si la variable está realmente controlada por el usuario y si existe algún tipo de saneamiento, validación o conversión. Y si existe algún tipo de mitigación, comprueba si es realmente eficaz.
El segundo paso solo se lleva a cabo cuando no podemos descartar la posibilidad de explotación en el primer paso. Entonces nos centraremos en la priorización. La prioridad se define por la probabilidad de que algo salga mal y la gravedad si saliera mal. Este segundo paso es menos claro, pero también depende de estimaciones subjetivas, por ejemplo, una variable controlada por el usuario cuando carecemos de un contexto completo.
Para la mayoría de las reglas, podemos resumir cómo hacerlo en un número razonable de «reglas generales», lo que hace que los modelos de razonamiento sean excesivos: suelen tener una precisión similar, pero su precio es significativamente más elevado.
Por qué funcionan los modelos de razonamiento pequeño
Algunas reglas son sorprendentemente complejas y los modelos no basados en el razonamiento tienen dificultades para comprenderlas. Imagina que utilizas exactamente el mismo espacio mental para cada palabra que dices: inicialmente alguien te pregunta: «¿cuánto es 1+1?». Luego, esa misma persona te pregunta «¿cuánto es 26248 + 346237?». Mientras que los modelos normales tienen dificultades con los distintos niveles de complejidad, los modelos de razonamiento pueden manejarlos simplemente utilizando más palabras para las entradas complejas y desglosando los problemas más grandes en subproblemas más pequeños y manejables.
Desafortunadamente, debido a que consumen más tokens, también suelen ser más caros. Sin embargo, los modelos estructurados como modelos de razonamiento se ven menos afectados por la reducción del tamaño del modelo que los modelos que no son de razonamiento. Hay dos razones para optar por modelos más grandes: (1) tienen más capacidad para almacenar más conocimientos (pero no es realmente necesario tener muchos conocimientos en el caso de la clasificación de vulnerabilidades). (2) Los modelos más grandes tienden a ser un poco más precisos por palabra. Sin embargo, los modelos de razonamiento pueden recuperarse de los errores gracias a su estructura de razonamiento. Por lo tanto, a pesar de consumir más tokens, en la práctica es factible trabajar con modelos más pequeños con un coste por token más bajo para compensar el mayor uso de tokens.
Recorrido de rutas en JavaScript
El recorrido de rutas es una regla en la que los modelos de razonamiento pueden realmente destacar, ya que son sorprendentemente complejos de clasificar. El recorrido de rutas es una vulnerabilidad por la que los usuarios finales podrían leer o escribir archivos fuera de un directorio previsto. Por ejemplo, imagina que Google Drive tuviera una carpeta dedicada a cada usuario por separado en un sistema de archivos como este:
GoogleDrive/userId1/
Google Drive/userId2/…La próxima vez que desees descargar uno de tus archivos, envía una solicitud GET desde tu navegador cliente a Google Drive, por ejemplo, con el nombre de archivo miPerroComiendoZapatos.jpg. Si ese archivo existe, la descarga comenzará inmediatamente. Pero, ¿qué pasa si pruebas con el siguiente nombre de archivo? ../userId2/miscontraseñas.txtSi Google Drive no hubiera protegido su back-end contra el recorrido de rutas, entonces sería posible descargar un «miscontraseñas.txtdel otro usuario, si ese archivo existe.
Diferentes ataques de recorrido de rutas
Para clasificar SAST de recorrido de rutas, necesitamos comprender los diferentes casos en los que algo es vulnerable o no. Comencemos con los casos más sencillos y vayamos aumentando gradualmente la complejidad.
Patrón 1: «../»
El problema evidente aquí es el patrón «../». Si lees o escribes en una ruta de archivo que contiene «../», podrías escape directorio previsto y leer o escribir en algún lugar que no era tu intención. Por lo tanto, si no se comprueba la presencia de «../» en la ruta de archivo y el archivo se especifica en el lado del cliente, existe una vulnerabilidad real. En los casos más graves, los piratas informáticos podrían leer archivos que contienen credenciales en tu sistema.
Patrón 2: «..\\»
Imagina que has comprobado «../», pero el código se ejecuta en un sistema Windows. Volverías a tener un problema, ya que el recorrido de rutas sigue siendo posible con los patrones «..\\». Hasta ahora todo bien, dos reglas generales que comprobar siguen siendo manejables, ¿verdad?
Patrón 3: «...»
Para obtener rutas bonitas y limpias sin perder barras, mucha gente utiliza funciones como path.resolve() o path.join()Aquí es donde empieza la diversión. Imagínate algo así:
if (userControlledSubPath.includes(‘../’) || userControlledSubPath.includes(‘..\\’)|| filename.includes(‘../’) || filename.includes(‘..\\’))
{
throw new Error(‘Path traversal attempt detected);
}
const filepath = path.join(HARDCODED_BASE_PATH, userControlledSubPath, filename);
return fs.readFileSync(filepath);Resulta que esto sigue siendo vulnerable: si un atacante utiliza userControlledSubPath === '..', el path.join seguirá interpretándolo como subir un directorio.
Sin embargo, el último argumento en path.join() es inmune a ese ataque. Si un atacante especificara «..» en el último argumento, el path.join() La función devolvería un directorio en lugar de una ruta de archivo, lo que daría lugar a una operación de lectura/escritura no válida.
Patrón 4: «/*»
En un nuevo ejemplo, volvimos a tener una prueba como esta:
if (filename.includes(‘..’))
{
throw new Error(‘Path traversal attempt detected);
}
const filepath = path.resolve(HARDCODED_BASE_PATH, filename);
return fs.readFileSync(filepath);Esto parece seguro, ¿verdad? La comprobación cubre los casos «..», «../» y «..\\»: ¡es elegante! Ahora viene la sorprendente forma en que esto sigue siendo vulnerable. Redoble de tambores... trrrrrrrrr... Cuando un argumento en path.resolve() comienza con una barra, ignora todos los argumentos anteriores. Por lo tanto, cuando un atacante hace algo como filename = /etc/passwd, entonces path.resolve() ignorará la ruta base codificada y la resolverá como /etc/passwdDa miedo, ¿verdad? Deberíamos haber comprobado también esa barra final. Ten en cuenta que al usar path.join() lo habría hecho seguro.
Apreciar la complejidad
Charlie Chaplin dijo una vez: «La simplicidad no es algo sencillo». Esto también se aplica aquí: existen soluciones sencillas y eficaces, pero primero hay que comprender la variedad de posibles vectores de ataque. La solución más sencilla y sólida contra el recorrido de rutas es resolver primero la ruta y comprobar si sigue comenzando con la ruta base prevista. No hay forma de eludir esa comprobación.
Sin embargo, el equipo de AutoTriage no tiene el lujo de poder elegir la solución. Necesitamos poder marcar las soluciones alternativas como seguras para no abrumar innecesariamente a los clientes con falsos positivos. Hasta ahora hemos visto cuatro vectores de ataque diferentes de recorrido de rutas y todos ellos vienen con comprobaciones específicas. Para cada uno de estos vectores de ataque, el LLM debe comprobar si es posible que se produzca con todos los requisitos para llevar a cabo un ataque con éxito o para descartar cualquier posibilidad de ataque.
A pesar de que los modelos de razonamiento no son el valor predeterminado para la mayoría de las reglas, son capaces de filtrar de forma segura el doble de falsos positivos en comparación con los modelos sin razonamiento para el recorrido de rutas en JavaScript. Eso supone un cambio revolucionario para reducción de ruido.
Protege tu software ahora.



.avif)
