VNX-930: Android app runs commands as root through su
CWE-930 is an OWASP Top Ten 2013 category (broken authentication and session management) with no code shape of its own; this rule reports the concrete device-level authorization signal it was generated for: Java or Kotlin code that launches the su binary to run commands as root, through Runtime.getRuntime().exec("su"), exec("su -c ..."), exec(new String[]{"su", ...}) or exec(arrayOf("su", ...)), new ProcessBuilder("su", ...), ProcessBuilder(listOf/Arrays.asList("su", ...)) or processBuilder.command("su", ...), with su named bare or by an absolute path (/system/xbin/su, /su/bin/su) and the argument list possibly starting on the next line; a command array whose first element is su assigned a few lines before the exec; and the libsuperuser Shell.SU.run(...) and early libsu Shell.su(...) root-shell helpers. Whatever the root shell runs bypasses the Android permission model. Not reported: root detection (which su, ls /system/xbin/su, File("/system/xbin/su").exists(), Shell.SU.available(), Superuser.apk checks), non-root shells (Shell.SH.run), other commands, comments and strings, and test code (src/test, src/androidTest, *Test.java).
| Field | Value |
|---|---|
| Rule ID | VNX-930 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, Kotlin |
| CWE | CWE-930 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | authorization-bypass-device android cwe-930 |
| Source | internal/sast/rules/vnx-930.rego |
Overview
CWE-930 is an OWASP Top Ten 2013 category (broken authentication and session management) with no code shape of its own; this rule reports the concrete device-level authorization signal it was generated for: Java or Kotlin code that launches the su binary to run commands as root, through Runtime.getRuntime().exec(“su”), exec(“su -c …”), exec(new String[]{“su”, …}) or exec(arrayOf(“su”, …)), new ProcessBuilder(“su”, …) or ProcessBuilder(listOf/Arrays.asList(“su”, …)), and a command array whose first element is su assigned a few lines before the exec. Whatever the root shell runs bypasses the Android permission model. Not reported: root detection (which su, File(“/system/xbin/su”).exists(), Superuser.apk checks), other commands, comments and strings.
Why This Matters
A command run through su runs as root, outside the Android sandbox and permission model. Any part of it built from input becomes root code execution, and the app only works on rooted devices.
What Gets Flagged
Process p = Runtime.getRuntime().exec("su");
Runtime.getRuntime().exec(new String[] { "su", "-c", cmd });
ProcessBuilder pb = new ProcessBuilder("su", "-c", cmd);
Runtime.getRuntime().exec(arrayOf("su", "-c", cmd))
What Is Not Flagged
// root detection, not root use
boolean rooted = new File("/system/xbin/su").exists();
Runtime.getRuntime().exec(new String[] { "which", "su" });
Runtime.getRuntime().exec("ls -l /data/local/tmp");
Remediation
- Use a platform API or a privileged system service with a narrow interface instead of a root shell.
- If root is unavoidable, never build the command from input, and run a fixed command list.
- For a confirmed false positive, add a
vulnetix-ignore: VNX-930comment on the line.
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-930
// nosec vnx-930
Or record an ignore rule: vulnetix ignore add --rule vnx-930 --reason "...". See Suppressing findings.