FlawOpen

flawopen.com/Command Injection/Java Runtime.exec()

¿Runtime.exec() en Java evita Command Injection?

CWE-78: OS Command InjectionPágina de referencia
Respuesta breve

Runtime.exec(String) no ejecuta un shell de forma implícita, así que los operadores de shell no se interpretan automáticamente. Aun así, la cadena se divide en programa y argumentos, y el texto no confiable puede cambiar los argumentos que recibe el programa. ProcessBuilder hace explícitos los límites; valida cada valor y limita el ejecutable y las opciones permitidas.

RIESGOSO
// La entrada del usuario se concatena en la cadena de comando
Runtime.getRuntime().exec(
  "approved-tool --input " + filename
);
MÁS SEGURO
// Ejecutable fijo y argumentos separados; valida filename primero
String safeName = validateFilename(filename);
new ProcessBuilder(
  "/opt/app/bin/approved-tool",
  "--input", safeName
).start();

La inyección de shell y la inyección de argumentos son distintas

Desde Java 18, Oracle marca Runtime.exec(String) como obsoleto por ser propenso a errores y recomienda exec(String[]) o ProcessBuilder. El overload de cadena separa tokens por espacios en blanco, lo que puede dividir argumentos como rutas con espacios. Runtime.exec(String) no inicia implícitamente sh ni otro shell; Oracle documenta que el overload convierte la cadena en un array de argumentos. Esto evita que los metacaracteres habituales actúen como sintaxis del shell, pero no vuelve segura la entrada: la tokenización aún puede crear argumentos adicionales, y el programa puede interpretar un argumento como opción. ProcessBuilder recibe una lista de cadenas para el ejecutable y sus argumentos; en plataformas comunes, cada elemento define un límite. Mantén fijo el ejecutable, valida los valores según la gramática esperada por el programa y rechaza o trata los valores que parezcan opciones. Usa -- solo si la documentación del programa garantiza ese comportamiento. No invoques explícitamente un shell, como sh -c, con datos no confiables.

Preguntas frecuentes

¿Que Runtime.exec(String) no use un shell significa que es seguro?

No. Reduce el riesgo de inyección en el shell para ese overload, pero aún puede haber inyección de argumentos. El programa puede interpretar entradas del atacante como opciones o nombres de archivo. Usa ProcessBuilder con ejecutable fijo y argumentos separados, y valida cada valor según el programa.

¿ProcessBuilder valida los argumentos por mí?

No. Construye la lista de programa y argumentos e inicia el proceso; no comprueba si son seguros o válidos. Aplica listas permitidas y validación en la aplicación, y sigue las reglas de argumentos documentadas por el programa.

Referencias

Véase también Inyección de comandos del SO (CWE-78): cómo funciona y cómo evitarla en todos los lenguajes — flawopen.com Riesgo de command injection en Node.js exec() Node.js exec() vs execFile(): diferencias y seguridad