Witr Source Detection Priority Order Explained: How Process Origin Is Determined

Witr detects the source of a process by sequentially running eleven platform‑specific checks in a fixed priority order, stopping at the first match to maximize accuracy and minimize false positives.

The open‑source project pranshuparmar/witr implements a deterministic source detection system that walks through process ancestry to identify how a process was launched. Understanding this priority hierarchy is essential for security analysts interpreting Witr's output and for contributors modifying detection behavior.

The Fixed Detection Priority List

The complete order is hardcoded in internal/source/detect.go at lines 55‑84. Each function receives the process tree and returns either a *model.Source or nil; the first non‑nil result wins.

Priority Function What It Detects
1 detectContainer Docker, podman, LXC, and other container runtimes
2 detectSSH SSH‑spawned processes
3 detectShell Interactive shell sessions
4 detectSystemd systemd units (services, sockets, timers)
5 detectLaunchd macOS launchd jobs
6 detectBsdRc BSD rc(8) init scripts
7 detectSupervisor Generic supervisors (supervisord, runit)
8 detectCron Cron‑scheduled jobs
9 detectWindowsService Windows services
10 detectInit Traditional init process (PID 1)
11 fallback SourceUnknown when no match exists

The code comment at lines 55‑57 explicitly states: "Detection order prioritizes platform‑specific init systems over generic supervisor detection to avoid false positives."

Why Container Detection Comes First

Container isolation represents the strongest boundary in modern deployment. A process inside a Docker or podman container may retain SSH or shell ancestors in its PID namespace, but the container context provides the most actionable security metadata. Detecting containers before SSH ensures that:

  • Forensic tools receive the most specific provenance
  • Container escape attempts are attributed to their runtime environment
  • Platform‑specific detections do not misclassify containerized workloads

Platform‑Specific Init Systems Before Generic Supervisors

The placement of detectSystemd, detectLaunchd, and detectBsdRc ahead of detectSupervisor prevents a critical accuracy problem. Supervisors like supervisord or runit often manage processes that systemd or launchd originally spawned. If generic supervisors were checked first, Witr would incorrectly label a systemd service as merely "supervised." The priority order ensures:

  • systemd claims its own services on Linux
  • launchd claims its jobs on macOS
  • BSD rc claims traditional BSD services
  • Supervisors only apply when no platform manager is present

Interactive Sessions Over Background Daemons

SSH and shell detection occupy slots 2 and 3 because they represent two distinct entry points for interactive user activity. This early placement distinguishes:

  • Administrator actions (detectSSH)
  • Local terminal sessions (detectShell)
  • Automated background processes (caught by later service managers)

Without this hierarchy, a user running commands inside an SSH session might be misclassified as originating from cron or a system service.

The Rationale for Lower‑Priority Detectors

Cron, Windows services, and the traditional init process appear later because they are either less specific or serve as catch‑all mechanisms:

  • detectCron identifies scheduled tasks that lack tighter integration with modern init systems
  • detectWindowsService applies only on Windows, where architecture differs substantially
  • detectInit serves legacy systems without systemd or equivalent
  • fallback returns SourceUnknown when ancestry is truncated or unrecognized—a common scenario on Windows

Complete Source Detection in Action

package main

import (
	"fmt"
	"github.com/pranshuparmar/witr/internal/source"
	"github.com/pranshuparmar/witr/internal/model"
)

// Containerized process: docker → bash → nginx
func exampleContainer() {
	procs := []model.Process{
		{Command: "dockerd", PID: 1},
		{Command: "bash", PID: 42, PPID: 1},
		{Command: "nginx", PID: 100, PPID: 42},
	}
	src := source.Detect(procs)
	fmt.Println(src.Type) // Output: model.SourceContainer
}

// Systemd service: systemd → nginx
func exampleSystemd() {
	procs := []model.Process{
		{Command: "systemd", PID: 1},
		{Command: "nginx", PID: 150, PPID: 1},
	}
	src := source.Detect(procs)
	fmt.Println(src.Type) // Output: model.SourceSystemd
}

// SSH session: sshd → bash → python
func exampleSSH() {
	procs := []model.Process{
		{Command: "sshd", PID: 1},
		{Command: "bash", PID: 200, PPID: 1},
		{Command: "python", PID: 250, PPID: 200},
	}
	src := source.Detect(procs)
	fmt.Println(src.Type) // Output: model.SourceSSH
}

Key Implementation Files

Understanding the Witr source detection priority requires familiarity with these files:

Summary

  • Witr's source detection priority is fixed and sequential, stopping at the first match
  • Containers take precedence due to their strong isolation boundaries
  • Platform‑specific init systems (systemd, launchd, BSD rc) outrank generic supervisors to prevent misclassification
  • SSH and shell detection captures interactive user sessions early
  • Cron, Windows services, init, and unknown serve as progressive fallbacks
  • The design balances accuracy (specificity) against safety (avoiding false negatives in security analysis)

Frequently Asked Questions

What happens if multiple detection criteria match a single process?

Only the first matching detection function in the priority list determines the source type. The sequential walk in internal/source/detect.go returns immediately upon finding a non‑nil result, so higher‑priority classifications always win.

Why does supervisor detection appear after systemd and launchd?

Generic supervisors like supervisord can manage processes originally spawned by systemd or launchd. Checking platform‑specific managers first prevents Witr from reporting a systemd service as merely "supervised," which would lose critical provenance information for incident response.

Can the detection order be customized at runtime?

No. The priority order is hardcoded in internal/source/detect.go as a fixed slice of detection functions. Modification requires recompiling from source, ensuring consistent behavior across all Witr deployments.

What does Witr report when no source is detected?

The fallback function returns SourceUnknown. This occurs when process ancestry is truncated—common on Windows—or when a process originates from an unrecognized manager. The explicit unknown state prevents false confidence in automated security workflows.

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 →