Code Injection

ID

kotlin.code_injection

Severity

critical

Resource

Injection

Language

Kotlin

Tags

CWE:95, NIST.SP.800-53, OWASP:2021:A3, PCI-DSS:6.5.1

Description

Improper neutralization of directives in dynamically evaluated code ('Eval Injection').

Code Injection vulnerabilities occur when an application dynamically executes code containing untrusted input from users.

Rationale

In Kotlin, while direct code execution vulnerabilities are less common than in some other languages due to its lack of built-in scripting features, risks still emerge through features like the use of reflection, expression evaluation libraries, or dynamic language integrations. But since Java 6, direct execution of code in scripting languages is available through the javax.script package.

Consider this vulnerable Java code snippet using a scripting engine:

import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import javax.script.ScriptException

fun main() {
    val input = "user input" // User-controlled input

    val manager = ScriptEngineManager()
    val engine: ScriptEngine = manager.getEngineByName("JavaScript")

    try {
        engine.eval("print('${input.replace("'", "\\'")}')")
    } catch (e: ScriptException) {
        e.printStackTrace()
    }
}

In this example, user input directly influences the script execution, potentially allowing an attacker to inject and execute arbitrary code by manipulating the input.

Remediation

To mitigate Code Injection vulnerabilities, follow these best practices:

  1. Avoid Dynamic Code Execution: Where possible, avoid using dynamic script execution or reflection with untrusted input.

  2. Input Validation and Sanitization: Assume all input is potentially malicious. Rigorously validate all user inputs to confirm they adhere to expected formats, and sanitize them (a whitelisting approach is recommended) to remove potentially harmful content.

  3. Canonicalization: Decode and canonicalize inputs to a standard internal representation before validation. This helps prevent bypassing input filters through encoding tricks

Below is a revised approach assuming the need for dynamic evaluation, where we add checks and log unexpected inputs:

import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import javax.script.ScriptException

fun main() {
    val input = "user input" // User-controlled input

    if (isValidInput(input)) {
        val manager = ScriptEngineManager()
        val engine: ScriptEngine = manager.getEngineByName("JavaScript")

        try {
            engine.eval("print('${input.replace("'", "\\'")}')")
        } catch (e: ScriptException) {
            e.printStackTrace()
        }
    } else {
        System.err.println("Invalid script input detected!")
    }
}

fun isValidInput(input: String): Boolean {
    // your validation logic
    // Example: basic check for potentially harmful content
    return !input.contains(Regex("[^a-zA-Z0-9 ]")) // allow only alphanumeric and spaces
}

This implementation incorporates input sanitization and validation to ensure that only valid characters are processed and logs anything deemed suspicious. By enforcing these approaches, the risk of code injection can be significantly reduced.

Configuration

The detector has the following configurable parameters:

  • sources, that indicates the source kinds to check.

  • neutralizations, that indicates the neutralization kinds to check.

Unless you need to change the default behavior, you typically do not need to configure this detector.

References