opseclint
A detection-coverage analyzer for the command line. Point it at a command, a script, or a post-exploitation playbook and it statically resolves each action to the MITRE ATT&CK technique(s) it implements, the host telemetry it emits, and the detections that would fire — each with a detectability score.
It answers one question: "what would a defender see?"
Who it's for
- Detection engineers validating coverage — "if an operator ran this, would my ruleset catch it, and with what telemetry?"
- Purple teams mapping an engagement's actions to expected detections before and after a test.
- Red teams operating under authorization who need to understand and report the telemetry footprint of a playbook.
Scope
opseclint describes detectability — the defensive signal an action generates. It is not an evasion tool: it does not recommend "quieter" alternatives or ways to defeat a detection. Absence of a finding means only that nothing in the knowledge base matched — it is never a claim that an action is stealthy.
Install
# or, from a checkout:
Usage
|
Real Sigma rules
By default, detection references in the seed KB are representative. Point
--sigma at a checkout of SigmaHQ/sigma
(or any directory of Sigma YAML) and opseclint indexes every rule by its ATT&CK
technique tag, then replaces each finding's references with the genuine rule
titles and UUIDs that match — Linux-relevant rules only.
# detection Sigma: Access To Sudoers File (2c9d1141-... ) (high confidence)
The ruleset is read at runtime and never bundled, so the binary stays
self-contained. The parsed index is cached to disk (keyed by a fingerprint of
the ruleset directory), so repeat runs against a large checkout skip re-parsing
— the report notes [cached] on a hit. The cache lives in the system temp dir
(override with OPSECLINT_CACHE_DIR) and invalidates automatically when the
ruleset changes; --no-sigma-cache bypasses it.
Platforms
Select the host telemetry model with --platform (default linux-auditd):
| Platform | Telemetry model |
|---|---|
linux-auditd |
Linux with auditd / EDR syscall events |
windows-sysmon |
Windows with Sysmon (Event IDs) / Security log |
macos-es |
macOS with Endpoint Security (ESF) / unified log |
Each platform has its own embedded knowledge base, so whoami resolves to Linux
execve() telemetry, a Windows Sysmon EID 1, or a macOS ESF NOTIFY_EXEC
depending on the target. Windows program names are normalized
(C:\…\certutil.exe → certutil). When combined with --sigma, rules are
filtered to the platform's logsource.product.
GitHub code scanning
--sarif emits SARIF 2.1.0, so findings can surface in a repo's Security →
Code scanning tab. Each finding maps to a rule (tagged with its ATT&CK
technique and a security-severity derived from the detectability score) and is
anchored to the line of the analyzed file. See .github/workflows/ci.yml
for a job that runs opseclint and uploads the results.
Use as a GitHub Action
opseclint ships a composite action (action.yml) that downloads
a released binary and analyzes a path in CI (Linux runners):
- uses: Gerrrt/opseclint@v0.1.0
with:
path: examples/
platform: linux-auditd # or windows-sysmon | macos-es
fail-threshold: "75" # optional: fail the job on a loud action
sarif-file: opseclint.sarif # optional: emit SARIF...
- uses: github/codeql-action/upload-sarif@v3 # ...then upload it
with:
sarif_file: opseclint.sarif
Inputs: path (required), platform, version (default latest),
sarif-file, fail-threshold, and args for anything else.
CI gating
--ci makes opseclint a gate: it exits non-zero when the loudest modeled action
meets or exceeds --threshold (default 50), so a team can fail a pipeline on
tradecraft that exceeds an agreed noise budget.
# .github/workflows/opsec.yml (example)
- run: opseclint playbooks/ --ci --threshold 75
Example playbooks
The examples/ directory has illustrative (benign-to-run)
playbooks to try it against:
Detectability score
A 0–100 estimate of how strongly an action surfaces in defensive telemetry (higher = louder), bucketed as:
| Score | Severity |
|---|---|
| 0–24 | LOW |
| 25–49 | MEDIUM |
| 50–74 | HIGH |
| 75–100 | CRITICAL |
How it works
- Parser (
parser.rs) — quote-aware tokenizer that strips comments andVAR=valueassignments, splits a line on control operators (; | & && ||), unwrapssudo/env/nohup/… and resolves each segment to a program + arguments. The raw line is preserved so substring rules still match. A preprocessing pass joins line continuations (trailing\,|,&&,||), resolves commands hidden in$(...)/ backtick substitutions, and handles here-docs — a here-doc body is skipped as data unless it feeds a shell interpreter, in which case each body line is analyzed at its real line. - Knowledge base (
data/knowledge*.json) — one KB per platform (Linux, Windows, macOS); each entry maps a command (or a raw pattern) to ATT&CK techniques, the telemetry it emits, representative Sigma-style detections, and a detectability score. - Analyzer (
analyzer.rs) — matches every action against the KB, deduplicates per line, and ranks findings loudest-first. - Report (
report.rs) — terminal or JSON output, plus the CI gate.
All KBs are embedded at compile time, so opseclint ships as a single static binary with no runtime dependencies.
Knowledge base schema
An entry matches either by command (with optional args_contains /
raw_contains refinements) or by raw_contains alone. Adding coverage is a
data change, not a code change.
Status & roadmap
v0.1 seeds three platforms: Linux / auditd (~60 entries), Windows /
Sysmon (~60 entries, including Active Directory tradecraft — Kerberoasting,
DCSync, ticket attacks, BloodHound/PowerView recon, and lateral movement), and
macOS / Endpoint Security (~28 entries — keychain, Gatekeeper/SIP, TCC,
launchd persistence, AppleScript). Together they cover the most common
post-exploitation actions across discovery, credential access, execution,
persistence, defense evasion, and container escape. On the roadmap:
- Deepen each KB further and add more EDR-specific telemetry mappings.
- A
--format sarifupload for Windows/macOS example runs in CI.
Detection references in the seed KB are representative of publicly available Sigma logic and should be validated against your deployed ruleset before you rely on them.
License
MIT