saltar al contenido
volver al mapa
técnica de prueba
etapa: build / PR
3 min de lectura

SAST

Rayos X del código sin ejecutar nada: encuentra patrones vulnerables antes del primer deploy.

SemgrepCodeQLSonarQubeCheckmarx

Qué es

(Static Application Security Testing) analiza el código fuente, el bytecode o el binario sin ejecutar el programa. El scanner busca construcciones peligrosas (concatenación de SQL, , criptografía débil, ) y señala archivo y línea, en el formato que el desarrollador ya consume.

La sigla esconde tres técnicas muy distintas: pattern matching (reglas textuales), análisis de flujo de datos (el famoso ) y análisis semántico. Sin entender las tres, el output del scanner parece magia, y los falsos positivos parecen un bug.

Del texto al AST

Antes de cualquier análisis, el código pasa por un parser y se convierte en un AST (): cada construcción del lenguaje se vuelve un nodo tipado, y el scanner navega ese árbol en lugar de leer texto suelto. Eso permite preguntar cosas como '¿existe un nodo de concatenación dentro de una llamada de query?'.

Una línea inocente de JavaScript se convierte en un árbol así:

sql.js → ASTtext
const sql = "SELECT * FROM users WHERE id = " + req.query.id

VariableDeclaration
  id:   Identifier "sql"
  init: BinaryExpression "+"
          left:  StringLiteral "SELECT * FROM users WHERE id = "
          right: MemberExpression
                   req.query.id

Source → sink: el corazón del análisis

El AST solo dice que existe una concatenación, no si es peligrosa. La pregunta de seguridad es otra: ¿este dato tiene un origen confiable? ¿Dónde termina?

El taint analysis (análisis de contaminación) responde siguiendo el dato: las fuentes no confiables (input del usuario, headers, query strings) se marcan como 'tainted'. El engine propaga esa marca por asignaciones, concatenaciones y llamadas de función, y dispara la alerta cuando la marca llega a un sink: un punto donde el dato se convierte en comando, query, HTML o ruta de archivo.

En el ejemplo de abajo, el flujo es completo: nace en req.query.id (source), atraviesa una concatenación (propagación) y termina dentro de db.query (sink):

server.js — vulnerablejavascript
app.get("/users", (req, res) => {
  const id = req.query.id;                                // SOURCE
  const sql = "SELECT * FROM users WHERE id = " + id;     // propagación
  db.query(sql, (err, rows) => res.json(rows));           // SINK
});

Qué reporta el scanner

El resultado no es 'existe una concatenación': es el camino completo, con el y la corrección sugerida. Algo como:

salida del scannertext
server.js:3
  SQL Injection (CWE-89) · alta
  taint:  req.query.id -> id -> sql -> db.query()
  fix:    usa una query parametrizada (placeholder $1)

La corrección que el engine acepta

Parametrizar la query interrumpe el taint: el valor del usuario deja de ser código y pasa a ser dato. En el lenguaje del taint analysis, el es un sanitizador (o barrier): el engine sabe que ese camino específico está limpio y deja de alertar en él.

server.js — corregidojavascript
app.get("/users", (req, res) => {
  const sql = "SELECT * FROM users WHERE id = $1";        // query fija
  db.query(sql, [req.query.id], (err, rows) => res.json(rows));
});

Dónde entra en el pipeline

Lo más temprano posible: los plugins de IDE y el pre-commit dan feedback en segundos, y el análisis completo corre en el PR y en el stage de build. Las reglas críticas incumplidas hacen fallar el build () y bloquean el merge.

Puntos fuertes

  • cobertura del 100% del código, incluidos los caminos que rara vez se ejecutan
  • encuentra la vulnerabilidad temprano, cuando corregir cuesta poco
  • no necesita un entorno en ejecución ni credenciales

Limitaciones

  • falsos positivos: cuando el engine no puede probar que el camino es seguro (un sanitizador personalizado, por ejemplo), alerta por precaución, y el triaje es trabajo humano
  • explosión de caminos: analizar todas las combinaciones de ejecución es caro; los engines usan heurísticas y pueden perder flujos raros
  • es ciego a la configuración de runtime, la infraestructura y el comportamiento real: territorio del DAST
SASTAnálisis estático: examina el código sin ejecutarlo. Encuentra problemas por análisis de flujo, no por adivinación.ver en el glosario →Deserialización inseguraReconstruir objetos a partir de bytes no confiables con un formato que puede instanciar tipos arbitrarios (serialización de Java, pickle). Los bytes pueden provocar la ejecución de código.ver en el glosario →XSScross-site scriptingInyección en una página web: la entrada no confiable se renderiza como HTML o script en el navegador de otro usuario. Haz escape en la salida según el contexto y agrega una Content-Security-Policy.ver en el glosario →Taint trackinganálisis de contaminaciónSeguir la marca de 'dato sucio' desde el source hasta el sink, propagándola por asignaciones y llamadas. Es el corazón del SAST moderno.ver en el glosario →ASTabstract syntax treeEl árbol de sintaxis que produce el parser: cada construcción del código se vuelve un nodo tipado, y las herramientas analizan el árbol en lugar de texto suelto.ver en el glosario →CWEcommon weakness enumerationEl identificador del TIPO de debilidad, la clase del error en el código. CWE-89 es SQL injection, CWE-79 es XSS. La distinción que confunde a todos: CWE es la categoría, CVE es una ocurrencia concreta de ella. Un CVE de SQL injection en tu framework va a referenciar el CWE-89.ver en el glosario →Prepared statementconsulta parametrizadaUna consulta cuya estructura se fija antes de suministrar cualquier valor, de modo que la base de datos no puede confundir datos con instrucciones.ver en el glosario →Quality gateLa compuerta explícita de un stage: 'falla el build si hay un hallazgo crítico nuevo'. Sin un criterio claro, el gate se vuelve una sugerencia.ver en el glosario →

conexiones en el mapa

actualizado el 14/10/2026 · fuentes para profundizar · reportar un error

en otros dominios

Estudia antes

Desbloquea

pon a prueba lo que entendiste

Cargando preguntas…