How witr Detects LD_PRELOAD by Inspecting Process Environment Variables

witr detects LD_PRELOAD by iterating through detection rules defined in internal/source/detect.go and matching them against the environment variables of each discovered process.

The open-source process inspector witr scans running processes for suspicious environment variables that indicate potential library injection attacks. By analyzing the Env slice populated from /proc/<pid>/environ on Linux, witr identifies when processes set LD_PRELOAD or similar dynamic linker variables. This detection mechanism helps security operators spot potential code injection attempts in real-time.

Detection Rules in internal/source/detect.go

The core detection logic resides in internal/source/detect.go, where a slice of rules maps environment variable patterns to warning messages. At line 40, the tool defines a specific rule for LD_PRELOAD that triggers when a process environment contains this variable.

Pattern Definition for LD_PRELOAD

The detection rule structure contains a pattern string and a warning message. For LD_PRELOAD, the rule appears as:

{ pattern: "LD_PRELOAD", warning: "Process sets LD_PRELOAD (potential library injection)" },

Similar rules exist for macOS-specific variables like DYLD_INSERT_LIBRARIES and DYLD_LIBRARY_PATH, as well as LD_LIBRARY_PATH for Linux systems.

Matching Algorithm

The evaluation logic iterates over both the detection rules and the process environment slice. For each environment variable entry, witr checks whether the string starts with the rule's pattern followed by an equals sign (=), or matches the pattern exactly. When a match occurs, the associated warning string appends to the process findings.

Capturing Process Environment Data

Before detection occurs, witr must collect environment variables from each running process. The platform-specific implementations in internal/proc/process_*.go handle this collection.

On Linux systems, internal/proc/process_linux.go reads the /proc/<pid>/environ pseudo-file for each discovered PID. This file contains null-delimited environment variable strings, which the parser converts into the Env []string field of the model.Process struct defined in model/process.go.

Implementation Walkthrough

The following simplified example demonstrates how witr evaluates environment variables against detection rules:

// Simplified detection logic from internal/source/detect.go
procEnv := []string{
    "PATH=/usr/bin",
    "LD_PRELOAD=/tmp/malicious.so",
    "HOME=/home/user",
}

warnings := []string{}
for _, rule := range detectRules {
    for _, env := range procEnv {
        if strings.HasPrefix(env, rule.pattern+"=") || env == rule.pattern {
            warnings = append(warnings, rule.warning)
        }
    }
}
// Result: warnings contains "Process sets LD_PRELOAD (potential library injection)"

When executed through the main entry point at cmd/witr/main.go, this logic surfaces warnings in the CLI output, displaying lines such as:


Process 1234 (myapp) – Process sets LD_PRELOAD (potential library injection)

Validating Detection with Unit Tests

The detection behavior is verified in internal/source/detect_test.go, which contains test cases ensuring that processes with LD_PRELOAD set generate the appropriate warnings while clean processes produce none. These tests validate both the presence and absence scenarios, confirming that the pattern matching correctly identifies injection attempts without false positives on legitimate environment variables.

Summary

  • witr defines detection patterns in internal/source/detect.go including specific rules for LD_PRELOAD at line 40
  • Platform-specific collectors in internal/proc/process_*.go populate the Env field by reading /proc/<pid>/environ on Linux
  • The matching algorithm checks if environment variables start with the pattern followed by = or match exactly
  • Detected violations surface as warning strings in the process listing output
  • Unit tests in internal/source/detect_test.go validate the detection accuracy

Frequently Asked Questions

What file contains the LD_PRELOAD detection rules in witr?

The detection rules reside in internal/source/detect.go, where line 40 specifically defines the LD_PRELOAD pattern with its associated warning message for potential library injection.

How does witr access environment variables from running processes?

On Linux, witr reads the /proc/<pid>/environ pseudo-file through the platform-specific implementation in internal/proc/process_linux.go, parsing the null-delimited contents into the Env []string field of the model.Process struct.

Does witr detect other library injection methods besides LD_PRELOAD?

Yes, the detection rules also include patterns for DYLD_INSERT_LIBRARIES and DYLD_LIBRARY_PATH on macOS, as well as LD_LIBRARY_PATH on Linux, covering multiple dynamic linker injection vectors.

Where are the detection tests located in the repository?

The unit tests validating the environment variable inspection logic are located in internal/source/detect_test.go, ensuring that processes setting injection-related variables trigger appropriate warnings.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →