Skip to main content

06. Malware Detection with eBPF

1. The Concept (ELI5)​

Traditional anti-virus works by looking at the "fingerprints" (hashes) of files saved on a computer. If the fingerprint matches known malware, it deletes the file.

However, modern attackers are clever. They use Fileless Malware. Instead of saving a file to the hard drive, they inject the malicious code directly into the computer's temporary memory (RAM) and run it from there. Because no file was ever saved, traditional anti-virus sees nothing.

eBPF solves this by monitoring behavior, not just files. If a program suddenly asks the kernel to create an invisible, memory-only execution space (like the memfd_create system call) and attempts to run code from it, eBPF catches the act in progress and stops it.

2. The Visual​

3. The Code​

Applications handling uploads or executing temporary scripts should rely on strictly managed temporary directories and avoid using underlying OS APIs that map memory to executable space unnecessarily.

Go​

❌ Vulnerable Code (Executing from Memory/Temp Files)

package main
import (
"io/ioutil"
"os"
"os/exec"
)
// Running unvalidated downloaded binaries directly from temp space
func executePayload(payload []byte) {
f, _ := ioutil.TempFile("", "exec-*")
f.Write(payload)
f.Close()
os.Chmod(f.Name(), 0755)

cmd := exec.Command(f.Name())
cmd.Run()
}

✅ Secure Code (Avoid dynamic execution)

package main
// Do not download and execute arbitrary binaries.
// Application functionality should be bundled at build time.
// If dynamic scripting is absolutely required, use a secure sandbox like WebAssembly (Wasm).
func safeExecution() {
// Rely on static, pre-compiled logic.
}

Python​

❌ Vulnerable Code (Executing dynamic strings)

def run_dynamic_code(user_input):
# exec() runs strings as Python code, acting like fileless execution
exec(user_input)

✅ Secure Code (Use AST Evaluation)

import ast

def safe_eval(user_input):
# literal_eval only evaluates safe data types (strings, numbers, tuples, dicts, booleans, and None)
return ast.literal_eval(user_input)

TypeScript / Node.js​

❌ Vulnerable Code (Executing memory buffers)

import { exec } from 'child_process';

function runBuffer(buffer: Buffer) {
// Creating a child process from raw buffered input
const proc = exec('node');
proc.stdin?.write(buffer);
proc.stdin?.end();
}

✅ Secure Code (Static execution only)

// Do not pipe external buffers into interpreter stdin.
// Ensure all executed logic exists on the immutable container filesystem.

4. The Guardrail​

To prevent attackers from dropping malware into running containers, we use Kubernetes Security Contexts to enforce a Read-Only Root Filesystem. This means even if an attacker gets RCE, they cannot download and save a malicious binary to the container disk.

Terraform (Kubernetes Provider): Read-Only Filesystem

resource "kubernetes_deployment" "secure_app" {
metadata {
name = "secure-app"
}
spec {
template {
spec {
container {
name = "app"
image = "my-app:1.0"

security_context {
# Prevents writing any malware to the container filesystem
read_only_root_filesystem = true
}
}
}
}
}
}