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

> Understand the witr source detection priority order. Learn how witr identifies process origins with eleven platform specific checks, ensuring accuracy and minimizing false positives.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: deep-dive
- Published: 2026-08-10

---

**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`](https://github.com/pranshuparmar/witr/blob/main/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

```go
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:

- [`internal/source/detect.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/detect.go) — central dispatcher implementing the ordered cascade
- `internal/source/container_*.go` — container runtime implementations
- [`internal/source/ssh.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/ssh.go) — SSH session identification
- [`internal/source/shell.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/shell.go) — interactive shell heuristics
- [`internal/source/systemd_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/systemd_linux.go) — Linux systemd integration
- [`internal/source/launchd_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/launchd_darwin.go) — macOS launchd integration
- [`internal/source/supervisor.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/supervisor.go) — generic supervisor logic
- [`internal/source/cron.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/cron.go) — cron job detection
- [`internal/source/service_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/service_windows.go) — Windows service enumeration
- [`internal/source/init.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/init.go) — fallback init detection

## 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`](https://github.com/pranshuparmar/witr/blob/main/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`](https://github.com/pranshuparmar/witr/blob/main/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.