Git Forensics for Detection Rules

Trace who changed a security detection rule, when, and why using Git.

Introduction

30 Second Summary

Security teams maintain detection rules that automatically flag suspicious activity inside their networks. When someone quietly weakens one of those rules, the team becomes blind to the exact threat it was designed to catch. Tracing who changed a rule, when, and why is a core skill in detection engineering.

In this project, you will use Git commands to investigate a simulated detection engineering repository where someone made a suspicious change to a critical exfiltration rule.

What You'll Build

You will conduct a full forensic investigation using Git, answering exactly who weakened a detection rule, when they did it, whether it was tied to an approved ticket, and how it compares to legitimate tuning changes made by the same team.

By the end of this project, you'll have:

  • Traced the full history of a detection rule file and identified exactly who modified the critical threshold line, when, and what they changed.
  • Flagged a suspicious commit by comparing its missing ticket reference and vague message against every other well-documented change in the repository.
  • Built a practiced Git forensics workflow combining git log, git blame, git show, and --grep to investigate any rule change in seconds.
  • Secret Mission: Write a formal investigation report correlating timestamps, authors, and missing ticket references across the entire repository.

Are there any prerequisites?

None. This project includes setup for all required tools. You just need a Mac with a terminal. The first step walks you through creating the entire simulated repository from scratch.

Before We Start

Before We Start...

Before we dive in, let's lock in what you're about to build and why it matters. Detection engineering teams store their security rules in Git, which means every change is traceable. Your job in this project is to use that traceability to investigate a suspicious rule change.

Set Up the Investigation Environment

To practice Git forensics, you need a repository with realistic commit history to investigate against. A real detection engineering repo might have thousands of commits, so you will work with a focused simulation instead.

In this step, you will run a setup script that creates a Git repository containing Sigma-format detection rules with 11 commits from 3 team members spanning April to June 2026.

In this step, get ready to:
  • Save and run the setup script to create the detection rules repository.
  • Confirm the repository has the expected commit history.
  • Open the repository in VS Code and browse the rule file structure.
Save the setup script

The setup script creates a Git repository with simulated detection rules and historical commits. You will save it as a file and then run it.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create a new file called setup-detection-repo.sh by running:
touch setup-detection-repo.sh
  • Confirm the file was created by running:
ls setup-detection-repo.sh

You should see setup-detection-repo.sh listed in the output.

  • Open the file in VS Code by running:
code setup-detection-repo.sh

What does this setup script do?

The script initializes a Git repository, creates detection rule YAML files (in Sigma format), and commits them with realistic author names, dates, and messages.

It simulates 3 months of activity from 3 team members: Sarah Chen, Marcus Rodriguez, and Jamie Park. One of the commits contains a suspicious change that you will investigate in later steps.

The script is long because it builds 11 commits with full rule file contents. You will paste it into VS Code in sections below.

  • In VS Code, paste the first section of the script (the header and directory setup):
#!/bin/bash

# Setup script for Detection Rules Audit project
# Creates a Git repository with realistic detection rule commit history

set -e

REPO_DIR="detection-rules-audit"

if [ -d "$REPO_DIR" ]; then
    echo "Error: Directory '$REPO_DIR' already exists."
    echo "Remove it first with: rm -rf $REPO_DIR"
    exit 1
fi

mkdir -p "$REPO_DIR"
cd "$REPO_DIR"
git init
git config user.email "learner@example.com"
git config user.name "Learner"

mkdir -p rules/data-exfiltration
mkdir -p rules/privilege-escalation
mkdir -p rules/lateral-movement
mkdir -p rules/execution
mkdir -p rules/collection
  • Directly below that, paste the start of Commit 1 (the mass file download rule):
# --- Commit 1: Initial rules (Sarah, April 1) ---
cat > rules/data-exfiltration/mass-file-download.yml << 'EOF'
title: Mass File Download from Internal File Shares
id: 8a3c1f2e-4b5d-6e7f-8a9b-0c1d2e3f4a5b
status: production
level: high
description: >
  Detects when a single user account downloads an unusually high
  number of files from internal SharePoint or network shares within
  a short time window. May indicate data staging for exfiltration.
author: Sarah Chen
date: 2026/04/01
modified: 2026/04/01
references:
  - https://attack.mitre.org/techniques/T1039/
tags:
  - attack.collection
  - attack.t1039
logsource:
  category: file_access
  product: microsoft365
detection:
  selection:
    EventType: FileDownloaded
    ShareType: internal
  condition: selection | count(TargetFilename) by UserName > 100
  timeframe: 1h
falsepositives:
  - Backup service accounts
  - Approved bulk migration activities
EOF
  • Continue pasting the unauthorized admin role rule (still part of Commit 1):
cat > rules/privilege-escalation/unauthorized-admin-role.yml << 'EOF'
title: Unauthorized Admin Role Assignment
id: 2b4c6d8e-1a3b-5c7d-9e0f-1a2b3c4d5e6f
status: production
level: critical
description: >
  Detects when a user is assigned a privileged admin role outside
  of the approved change management process. Excludes known
  automation service accounts.
author: Sarah Chen
date: 2026/04/01
modified: 2026/04/01
references:
  - https://attack.mitre.org/techniques/T1098/
tags:
  - attack.privilege_escalation
  - attack.t1098
logsource:
  category: audit
  product: azure_ad
detection:
  selection:
    Operation: Add member to role
    RoleName|contains:
      - Global Administrator
      - Privileged Role Administrator
      - Security Administrator
  filter_automation:
    ActorUserName: svc-identity-governance@acme-corp.com
  condition: selection and not filter_automation
falsepositives:
  - Emergency break-glass account usage
  - Approved role assignments via PIM
EOF
  • Paste the git commit command that records Commit 1:
git add -A
GIT_AUTHOR_DATE="2026-04-01T09:15:00" GIT_COMMITTER_DATE="2026-04-01T09:15:00" \
git commit --author="Sarah Chen <sarah.chen@acme-corp.com>" \
-m "Initialize detection rules repository

Add initial rule set for internal threat detection:
- Mass file download detection (T1039)
- Unauthorized admin role assignment (T1098)

Part of detection engineering program kickoff.
Ref: SOC-4500"
  • Paste Commit 2 (the after-hours VPN rule):
# --- Commit 2: After-hours VPN rule (Sarah, April 8) ---
cat > rules/lateral-movement/after-hours-vpn.yml << 'EOF'
title: After-Hours VPN Access from Unusual Location
id: 3c5d7e9f-2b4c-6d8e-0a1b-2c3d4e5f6a7b
status: production
level: medium
description: >
  Detects VPN connections established outside business hours
  (before 6 AM or after 10 PM local time) from geographic
  locations not previously associated with the user account.
author: Sarah Chen
date: 2026/04/08
modified: 2026/04/08
references:
  - https://attack.mitre.org/techniques/T1133/
tags:
  - attack.initial_access
  - attack.t1133
logsource:
  category: vpn
  product: cisco_anyconnect
detection:
  selection:
    EventType: VPNConnect
    ConnectionTime|time:
      - ">=22:00"
      - "<=06:00"
  filter_known_locations:
    SourceGeoCountry: US
    SourceGeoCity|contains:
      - Portland
      - Seattle
      - San Francisco
  condition: selection and not filter_known_locations
  timeframe: 24h
  • Continue with the rest of Commit 2 (the false positives section and the git commit):
falsepositives:
  - Employees traveling internationally
  - On-call rotation staff working incidents
EOF

git add -A
GIT_AUTHOR_DATE="2026-04-08T14:30:00" GIT_COMMITTER_DATE="2026-04-08T14:30:00" \
git commit --author="Sarah Chen <sarah.chen@acme-corp.com>" \
-m "Add after-hours VPN access detection rule

Detects VPN connections outside business hours from unusual
geographic locations. Targets potential compromised credential
usage or unauthorized remote access.

Ref: SOC-4500"
  • Paste Commit 3 (the PowerShell execution rule):
# --- Commit 3: PowerShell rule (Marcus, April 15) ---
cat > rules/execution/suspicious-powershell.yml << 'EOF'
title: Suspicious PowerShell Execution with Encoded Commands
id: 4d6e8f0a-3c5d-7e9f-1b2c-3d4e5f6a7b8c
status: production
level: high
description: >
  Detects PowerShell execution with encoded command arguments,
  download cradles, or known malicious command patterns on
  corporate endpoints.
author: Marcus Rodriguez
date: 2026/04/15
modified: 2026/04/15
references:
  - https://attack.mitre.org/techniques/T1059/001/
tags:
  - attack.execution
  - attack.t1059.001
logsource:
  category: process_creation
  product: windows
detection:
  selection_encoded:
    Image|endswith: \powershell.exe
    CommandLine|contains:
      - "-enc"
      - "-EncodedCommand"
      - "-e "
  • Continue with the rest of Commit 3:
  selection_download:
    Image|endswith: \powershell.exe
    CommandLine|contains:
      - "IEX"
      - "Invoke-Expression"
      - "Net.WebClient"
      - "DownloadString"
  condition: selection_encoded or selection_download
falsepositives:
  - Enterprise software deployment scripts
  - SCCM client operations
EOF

git add -A
GIT_AUTHOR_DATE="2026-04-15T11:00:00" GIT_COMMITTER_DATE="2026-04-15T11:00:00" \
git commit --author="Marcus Rodriguez <marcus.rodriguez@acme-corp.com>" \
-m "Add suspicious PowerShell execution detection

Covers encoded command usage and download cradle patterns
commonly used in initial access and execution phases.

Ref: SOC-4500"
  • Paste Commit 4 (tuning the mass download threshold from 100 to 50):
# --- Commit 4: Tune mass download threshold (Sarah, April 22) ---
cat > rules/data-exfiltration/mass-file-download.yml << 'EOF'
title: Mass File Download from Internal File Shares
id: 8a3c1f2e-4b5d-6e7f-8a9b-0c1d2e3f4a5b
status: production
level: high
description: >
  Detects when a single user account downloads an unusually high
  number of files from internal SharePoint or network shares within
  a short time window. May indicate data staging for exfiltration.
author: Sarah Chen
date: 2026/04/01
modified: 2026/04/22
references:
  - https://attack.mitre.org/techniques/T1039/
tags:
  - attack.collection
  - attack.t1039
logsource:
  category: file_access
  product: microsoft365
detection:
  selection:
    EventType: FileDownloaded
    ShareType: internal
  condition: selection | count(TargetFilename) by UserName > 50
  timeframe: 1h
falsepositives:
  - Backup service accounts
  - Approved bulk migration activities
EOF
  • Continue with the git commit for Commit 4:
git add -A
GIT_AUTHOR_DATE="2026-04-22T16:45:00" GIT_COMMITTER_DATE="2026-04-22T16:45:00" \
git commit --author="Sarah Chen <sarah.chen@acme-corp.com>" \
-m "Lower mass download threshold from 100 to 50 files

Post-incident review from SOC-4521 showed attacker exfiltrated
78 files in a single session without triggering alert. Reducing
threshold to 50 files/hour to catch similar activity.

Reviewed with SOC lead - acceptable FP increase estimated at
2-3 additional alerts per week.

Ref: SOC-4521"
  • Paste Commit 5 (fixing PowerShell false positives):
# --- Commit 5: Fix PowerShell FP (Marcus, May 3) ---
cat > rules/execution/suspicious-powershell.yml << 'EOF'
title: Suspicious PowerShell Execution with Encoded Commands
id: 4d6e8f0a-3c5d-7e9f-1b2c-3d4e5f6a7b8c
status: production
level: high
description: >
  Detects PowerShell execution with encoded command arguments,
  download cradles, or known malicious command patterns on
  corporate endpoints.
author: Marcus Rodriguez
date: 2026/04/15
modified: 2026/05/03
references:
  - https://attack.mitre.org/techniques/T1059/001/
tags:
  - attack.execution
  - attack.t1059.001
logsource:
  category: process_creation
  product: windows
detection:
  selection_encoded:
    Image|endswith: \powershell.exe
    CommandLine|contains:
      - "-enc"
      - "-EncodedCommand"
      - "-e "
  • Continue with the rest of Commit 5:
  selection_download:
    Image|endswith: \powershell.exe
    CommandLine|contains:
      - "IEX"
      - "Invoke-Expression"
      - "Net.WebClient"
      - "DownloadString"
  filter_sccm:
    ParentImage|endswith: \CcmExec.exe
  filter_deployment:
    ParentImage|endswith: \svchost.exe
    CommandLine|contains: "ConfigurationManager"
  condition: (selection_encoded or selection_download) and not filter_sccm and not filter_deployment
falsepositives:
  - Enterprise software deployment scripts
  - SCCM client operations (now filtered)
EOF

git add -A
GIT_AUTHOR_DATE="2026-05-03T10:20:00" GIT_COMMITTER_DATE="2026-05-03T10:20:00" \
git commit --author="Marcus Rodriguez <marcus.rodriguez@acme-corp.com>" \
-m "Fix false positives in PowerShell detection rule

SCCM agent (CcmExec.exe) legitimately spawns PowerShell with
encoded commands during software deployments. Adding parent
process filter to exclude SCCM-initiated executions.

Was generating ~40 FP alerts/day across the fleet.

Ref: SOC-4587"
  • Paste Commit 6 (USB mass storage detection by Jamie):
# --- Commit 6: USB detection (Jamie, May 12) ---
cat > rules/collection/usb-mass-storage.yml << 'EOF'
title: USB Mass Storage Device Connected
id: 5e7f9a1b-4d6e-8f0a-2c3d-4e5f6a7b8c9d
status: production
level: medium
description: >
  Detects when a USB mass storage device is connected to a
  corporate endpoint. Policy requires all removable media
  usage to be pre-approved.
author: Jamie Park
date: 2026/05/12
modified: 2026/05/12
references:
  - https://attack.mitre.org/techniques/T1052/001/
tags:
  - attack.exfiltration
  - attack.t1052.001
logsource:
  category: driver_load
  product: windows
detection:
  selection:
    EventType: DeviceConnect
    DeviceClass: USB_MASS_STORAGE
  filter_approved:
    DeviceVendorId:
      - "VID_0781"
      - "VID_0951"
    DeviceApprovalStatus: approved
  condition: selection and not filter_approved
  • Continue with the rest of Commit 6:
falsepositives:
  - Pre-approved encrypted USB devices
  - IT hardware team provisioning
EOF

git add -A
GIT_AUTHOR_DATE="2026-05-12T09:30:00" GIT_COMMITTER_DATE="2026-05-12T09:30:00" \
git commit --author="Jamie Park <jamie.park@acme-corp.com>" \
-m "Add USB mass storage detection rule

Detect unauthorized removable media connections per
corporate acceptable use policy. Filters out approved
vendor devices with valid approval status.

Ref: SOC-4598"
  • Paste Commit 7 (VPN rule tuning by Jamie):
# --- Commit 7: VPN rule tuning (Jamie, May 20) ---
cat > rules/lateral-movement/after-hours-vpn.yml << 'EOF'
title: After-Hours VPN Access from Unusual Location
id: 3c5d7e9f-2b4c-6d8e-0a1b-2c3d4e5f6a7b
status: production
level: medium
description: >
  Detects VPN connections established outside business hours
  (before 6 AM or after 10 PM local time) from geographic
  locations not previously associated with the user account.
author: Sarah Chen
date: 2026/04/08
modified: 2026/05/20
references:
  - https://attack.mitre.org/techniques/T1133/
tags:
  - attack.initial_access
  - attack.t1133
logsource:
  category: vpn
  product: cisco_anyconnect
detection:
  selection:
    EventType: VPNConnect
    ConnectionTime|time:
      - ">=22:00"
      - "<=06:00"
  filter_known_locations:
    SourceGeoCountry: US
    SourceGeoCity|contains:
      - Portland
      - Seattle
      - San Francisco
  • Continue with the rest of Commit 7:
  filter_oncall:
    UserGroup: oncall-rotation
  condition: selection and not filter_known_locations and not filter_oncall
  timeframe: 24h
falsepositives:
  - Employees traveling internationally
  - On-call rotation staff working incidents (now filtered)
EOF

git add -A
GIT_AUTHOR_DATE="2026-05-20T15:10:00" GIT_COMMITTER_DATE="2026-05-20T15:10:00" \
git commit --author="Jamie Park <jamie.park@acme-corp.com>" \
-m "Add on-call rotation exclusion to VPN rule

On-call engineers connecting at 2-3 AM to respond to pages
were triggering this rule nightly. Adding UserGroup filter
for the oncall-rotation group.

Confirmed with SOC lead that on-call activity is monitored
separately via PagerDuty integration.

Ref: SOC-4612"
  • Paste Commit 8 (privilege escalation tuning by Marcus):
# --- Commit 8: Priv esc tuning (Marcus, June 2) ---
cat > rules/privilege-escalation/unauthorized-admin-role.yml << 'EOF'
title: Unauthorized Admin Role Assignment
id: 2b4c6d8e-1a3b-5c7d-9e0f-1a2b3c4d5e6f
status: production
level: critical
description: >
  Detects when a user is assigned a privileged admin role outside
  of the approved change management process. Excludes known
  automation service accounts.
author: Sarah Chen
date: 2026/04/01
modified: 2026/06/02
references:
  - https://attack.mitre.org/techniques/T1098/
tags:
  - attack.privilege_escalation
  - attack.t1098
logsource:
  category: audit
  product: azure_ad
detection:
  selection:
    Operation: Add member to role
    RoleName|contains:
      - Global Administrator
      - Privileged Role Administrator
      - Security Administrator
  filter_automation:
    ActorUserName|contains:
      - svc-identity-governance@acme-corp.com
      - svc-provisioning@acme-corp.com
  condition: selection and not filter_automation
  • Continue with the rest of Commit 8:
falsepositives:
  - Emergency break-glass account usage
  - Approved role assignments via PIM
  - Automated provisioning during onboarding
EOF

git add -A
GIT_AUTHOR_DATE="2026-06-02T13:45:00" GIT_COMMITTER_DATE="2026-06-02T13:45:00" \
git commit --author="Marcus Rodriguez <marcus.rodriguez@acme-corp.com>" \
-m "Add provisioning service account to priv esc exclusions

New automated onboarding system uses svc-provisioning account
to assign Security Reader role during employee setup. This was
generating 15-20 FP alerts per day on new hire onboarding days.

Verified svc-provisioning only assigns Security Reader (not
Global Admin or Priv Role Admin) but the rule matches on any
admin role assignment operation.

Ref: SOC-4701"
  • Paste Commit 9 (the suspicious change by Jamie):
# --- Commit 9: THE SUSPICIOUS CHANGE (Jamie, June 10) ---
cat > rules/data-exfiltration/mass-file-download.yml << 'EOF'
title: Mass File Download from Internal File Shares
id: 8a3c1f2e-4b5d-6e7f-8a9b-0c1d2e3f4a5b
status: production
level: high
description: >
  Detects when a single user account downloads an unusually high
  number of files from internal SharePoint or network shares within
  a short time window. May indicate data staging for exfiltration.
author: Sarah Chen
date: 2026/04/01
modified: 2026/06/10
references:
  - https://attack.mitre.org/techniques/T1039/
tags:
  - attack.collection
  - attack.t1039
logsource:
  category: file_access
  product: microsoft365
detection:
  selection:
    EventType: FileDownloaded
    ShareType: internal
  condition: selection | count(TargetFilename) by UserName > 500
  timeframe: 1h
falsepositives:
  - Backup service accounts
  - Approved bulk migration activities
  - End-of-quarter reporting
EOF
  • Continue with the git commit for Commit 9:
git add -A
GIT_AUTHOR_DATE="2026-06-10T21:47:00" GIT_COMMITTER_DATE="2026-06-10T21:47:00" \
git commit --author="Jamie Park <jamie.park@acme-corp.com>" \
-m "Update exfiltration rule parameters"
  • Paste Commit 10 (email forwarding detection by Sarah):
# --- Commit 10: Email forwarding rule (Sarah, June 18) ---
cat > rules/data-exfiltration/suspicious-email-forwarding.yml << 'EOF'
title: Suspicious Email Forwarding Rule Created
id: 6f8a0b2c-5e7f-9a1b-3d4e-5f6a7b8c9d0e
status: production
level: high
description: >
  Detects when a mailbox forwarding rule is created that sends
  email to an external domain. Common technique for persistent
  data exfiltration via email.
author: Sarah Chen
date: 2026/06/18
modified: 2026/06/18
references:
  - https://attack.mitre.org/techniques/T1114/003/
tags:
  - attack.collection
  - attack.t1114.003
logsource:
  category: audit
  product: microsoft365
detection:
  selection:
    Operation:
      - New-InboxRule
      - Set-InboxRule
    Parameters|contains:
      - ForwardTo
      - ForwardAsAttachmentTo
      - RedirectTo
  filter_internal:
    ForwardingAddress|endswith: "@acme-corp.com"
  condition: selection and not filter_internal
  • Continue with the rest of Commit 10:
falsepositives:
  - Approved external forwarding for legal holds
  - Executive assistant shared mailbox configurations
EOF

git add -A
GIT_AUTHOR_DATE="2026-06-18T10:30:00" GIT_COMMITTER_DATE="2026-06-18T10:30:00" \
git commit --author="Sarah Chen <sarah.chen@acme-corp.com>" \
-m "Add suspicious email forwarding rule detection

Detect creation of mailbox rules that forward email externally.
Addresses gap identified in Q2 threat assessment - email
forwarding is a common persistence mechanism for data theft.

Ref: SOC-4738"
  • Paste Commit 11 (expanded PowerShell coverage by Marcus):
# --- Commit 11: PowerShell update (Marcus, June 25) ---
cat > rules/execution/suspicious-powershell.yml << 'EOF'
title: Suspicious PowerShell Execution with Encoded Commands
id: 4d6e8f0a-3c5d-7e9f-1b2c-3d4e5f6a7b8c
status: production
level: high
description: >
  Detects PowerShell execution with encoded command arguments,
  download cradles, or known malicious command patterns on
  corporate endpoints.
author: Marcus Rodriguez
date: 2026/04/15
modified: 2026/06/25
references:
  - https://attack.mitre.org/techniques/T1059/001/
tags:
  - attack.execution
  - attack.t1059.001
logsource:
  category: process_creation
  product: windows
detection:
  selection_encoded:
    Image|endswith: \powershell.exe
    CommandLine|contains:
      - "-enc"
      - "-EncodedCommand"
      - "-e "
      - "-ec "
  • Continue with the rest of Commit 11:
  selection_download:
    Image|endswith: \powershell.exe
    CommandLine|contains:
      - "IEX"
      - "Invoke-Expression"
      - "Net.WebClient"
      - "DownloadString"
      - "Invoke-WebRequest"
      - "curl "
  filter_sccm:
    ParentImage|endswith: \CcmExec.exe
  filter_deployment:
    ParentImage|endswith: \svchost.exe
    CommandLine|contains: "ConfigurationManager"
  condition: (selection_encoded or selection_download) and not filter_sccm and not filter_deployment
falsepositives:
  - Enterprise software deployment scripts
  - SCCM client operations (filtered)
EOF

git add -A
GIT_AUTHOR_DATE="2026-06-25T09:15:00" GIT_COMMITTER_DATE="2026-06-25T09:15:00" \
git commit --author="Marcus Rodriguez <marcus.rodriguez@acme-corp.com>" \
-m "Expand PowerShell detection coverage

Add additional encoded command variants (-ec flag) and
download cradle patterns (Invoke-WebRequest, curl) based
on purple team exercise findings.

Ref: SOC-4756"
  • Finally, paste the closing output section of the script:
echo ""
echo "================================================"
echo "  Detection Rules Audit Repository Created!"
echo "================================================"
echo ""
echo "Repository: $(pwd)"
echo "Commits: $(git rev-list --count HEAD)"
echo "Rules: $(find rules -name '*.yml' | wc -l | tr -d ' ')"
echo ""
echo "You are ready to start investigating!"
echo ""
  • Save the file in VS Code by pressing Cmd+S (macOS) or Ctrl+S (Windows).

Script looks overwhelming?

You do not need to understand every line of this script. Its only job is to create a practice repository so you can investigate it with Git commands in the next steps.

If you accidentally missed a section, the script will fail with a syntax error when you run it. If that happens, delete the file, re-create it, and paste each section carefully in order.

Help me fix a syntax error in my setup script

Run the script and confirm the repository

The script creates the entire simulated repository with one command. It takes a few seconds to generate all 11 commits.

  • Switch back to your Terminal and run the setup script:
bash setup-detection-repo.sh

You should see a success message showing the repository path, 11 commits, and 6 rules.

Seeing 'Directory already exists' error?

This means the script was run before. Remove the old directory and try again:

rm -rf detection-rules-audit
bash setup-detection-repo.sh

Help me troubleshoot the setup script failing

  • Change into the newly created repository directory by running:
cd detection-rules-audit

Before you check the commit history, how many commits do you think git log --oneline will show?

  • Verify the repository was created correctly by running:
git log --oneline

You should see 11 commits listed, with the most recent being "Expand PowerShell detection coverage".

Seeing fewer than 11 commits?

If the commit count is wrong, the script may have failed partway through. Go back to your Desktop, remove the directory with rm -rf detection-rules-audit, fix any missing sections in your script file, and run it again.

Help me figure out why my repo has the wrong number of commits

Open the repository in VS Code
  • Open the repository in VS Code by running:
code .

What is in this repository?

The rules/ directory contains detection rules organized by MITRE ATT&CK tactic:

  • data-exfiltration/ contains rules detecting data theft attempts.
  • privilege-escalation/ contains rules detecting unauthorized role changes.
  • lateral-movement/ contains rules detecting unusual network access.
  • execution/ contains rules detecting malicious command execution.
  • collection/ contains rules detecting data staging on endpoints.
  • In the VS Code Explorer sidebar on the left, expand the rules/ folder.
  • Click on any .yml file to see its contents. Each file is a Sigma-format detection rule with a title, detection logic, and metadata.

Your investigation environment is ready. Next up, you will use git log with file path filtering to trace the full history of a specific detection rule.

Trace a Rule's Evolution with git log

Your investigation environment is ready with a full detection rules repository and 11 commits to explore.

Before you can investigate a specific suspicious change, you need to see the full timeline of modifications to a rule file. A rule that was changed multiple times tells a different story than one changed once.

In this step, get ready to:
  • View commit history for a specific rule file using path filtering.
  • Read full diffs to see exactly what changed in each commit.
  • Compare commit patterns between rules to spot anomalies.
View the commit history for a single rule file

The git log command can filter its output to show only commits that affected a specific file path. This lets you isolate the history of one rule without scrolling through all 11 commits in the repository.

  • View only the commits that touched the mass file download rule by running this command:
git log --oneline -- rules/data-exfiltration/mass-file-download.yml

What does this command do?

  • git log shows commit history in reverse chronological order (newest first).
  • --oneline compresses each commit to a single line showing its short hash and message.
  • The -- separator followed by a file path limits output to commits that modified that specific file.

You should see exactly 3 commits listed. These are the original creation, a threshold reduction, and a later parameter update.

Seeing 'does not have any commits yet'?

Make sure you are inside the detection-rules-audit directory, not the parent folder where the setup script lives.

Check the file path for typos. The path must be exactly rules/data-exfiltration/mass-file-download.yml.

Help me troubleshoot why git log isn't showing commits for my rule file.

Read the full diffs to see what changed

The --oneline view shows you which commits touched the file, but not what they actually changed. The -p flag shows the full patch (diff) introduced in each commit.

Before you run the next command, think about what you expect to see. The rule currently has a threshold of 500 files. Do you think that's what it started at, or has it changed over time?

  • View the full diffs for every commit that touched this rule file by running:
git log -p -- rules/data-exfiltration/mass-file-download.yml

Scroll through the output from top to bottom. You are reading the commits in reverse chronological order, so the most recent change appears first.

What should I see?

The diffs reveal a clear threshold progression across the 3 commits:

  • The most recent commit changed the threshold from > 50 to > 500. Its message just says "Update exfiltration rule parameters". No ticket, no explanation.
  • The middle commit lowered the threshold from > 100 to > 50. Its message references SOC-4521 and explains exactly why.
  • The oldest commit created the file with the original threshold of > 100.

Something looks wrong. The team tightened the rule to 50 after a real incident, and then someone raised it all the way to 500 with no explanation.

Compare against a well-documented rule

You spotted a vague commit on the exfiltration rule, but maybe the team just doesn't write detailed messages. You need a baseline for comparison. The PowerShell detection rule was also modified multiple times.

  • View the commit history for the PowerShell rule by running:
git log --oneline --all -- rules/execution/suspicious-powershell.yml

You should see 3 commits for this rule as well. Read the commit messages. Every single one references a SOC ticket and clearly explains the reasoning behind the change.

Why does this comparison matter?

The PowerShell rule proves the team has a clear norm: reference a ticket, explain the business impact, and justify the change. The exfiltration rule's most recent commit breaks all of those norms.

This is the difference between a pattern and a coincidence. One vague commit could be laziness. One vague commit that breaks an otherwise consistent pattern is worth investigating.

You have now confirmed the suspicious commit. The message "Update exfiltration rule parameters" stands out because it has no ticket reference while every other tuning commit in the repository does.

You can now trace the full timeline of a rule's changes and spot when something doesn't fit. Next up, you will use git blame to pinpoint exactly who modified the suspicious threshold line and when they did it.

Identify Who Modified a Rule with git blame

In the previous step, you spotted a suspicious commit in the git log output. The message "Update exfiltration rule parameters" had no ticket reference, and the diff showed the threshold jumping from 50 to 500.

But git log shows commits in reverse chronological order. It tells you WHAT changed, but not exactly who last touched each individual line of the file. git blame solves this by annotating every single line with the commit that last modified it, pinpointing exactly which person changed the detection threshold.

In this step, get ready to:
  • Run git blame to see who last modified each line of the suspicious rule file.
  • Use the -L flag to isolate specific line ranges without scrolling through the entire file.
  • Compare blame output across rule files to see how multiple authors contribute to a single file over time.
Blame the mass file download rule

While git log showed you which commits touched the file, git blame goes line-by-line. Each line of the file is annotated with the commit hash, author, date, and the content itself.

  • Run the following command to see per-line annotation for the suspicious rule file:
git blame rules/data-exfiltration/mass-file-download.yml

What does this output show?

Each line of the file now shows four things: the short commit hash, the author's name, the date, and the actual file content.

Scroll through the output and find the line containing > 500 in the detection condition. Note the author name and the commit hash shown at the start of that line.

You should see "Jamie Park" next to the line containing > 500, with a commit date of 2026-06-10 at 21:47. That is a late evening change.

Not sure which line to look for?

Look for the condition: line in the output. It contains count(TargetFilename) by UserName > 500. The blame annotation before that line shows the author and date.

Help me find the suspicious line in my git blame output.

Narrow down with the -L flag

Scrolling through 29 lines of blame output works for a small file. In a real repository, rule files can be hundreds of lines long. The -L flag lets you specify a line range to focus on.

  • Isolate the lines around the suspicious changes by running:
git blame -L 28,30 rules/data-exfiltration/mass-file-download.yml

What does the -L flag do?

-L 28,30 tells git blame to only annotate lines 28 through 30. This isolates the exact area you care about without scrolling through the entire file.

You should see Jamie Park's name attributed to the modified lines in this range. In a larger file with hundreds of lines, this technique saves significant time.

Adjust line numbers to your output

If the line numbers in your full git blame output look slightly different, adjust the -L range to match what you see. The important thing is to target the lines Jamie modified.

Compare with a well-maintained rule file

Seeing one file's blame output is useful. Comparing it to a file with a healthier change history helps you understand what normal collaboration looks like.

  • Run git blame on the PowerShell rule file to see a multi-author history:
git blame rules/execution/suspicious-powershell.yml

What should I notice here?

This file shows multiple authors touching different sections. Marcus Rodriguez authored the filter additions (the filter_sccm and filter_deployment blocks) while the original detection logic still attributes to his initial commit.

This is what a healthy detection rule looks like over time. Multiple engineers contribute changes, and git blame gives you a clear picture of who owns each section.

Notice how different commit dates and authors appear throughout the file. This is normal team collaboration on shared rules.

Seeing only one author for the whole file?

Make sure you are running the blame command on rules/execution/suspicious-powershell.yml (not the mass-file-download rule). The PowerShell rule has been modified by Marcus in multiple commits with different dates.

Help me understand why my git blame output only shows one author.

Confirm your findings

Before you move on, predict what you expect to see. If you run git blame on the mass download rule one more time, which author do you expect on the threshold line, and what time was the commit made?

  • Confirm by running:
git blame rules/data-exfiltration/mass-file-download.yml

The line containing > 500 shows "Jamie Park" as the author, with a commit date of June 10, 2026 at 21:47. That is a late evening commit. Make a note of the commit hash shown at the start of that line. You will need it in the next step.

You now know WHO made the change and WHEN, down to the exact line. Next, you will use git show to inspect the full commit diff and see exactly what was removed and what was added.

Inspect the Suspicious Commit with git show

You now know who changed the detection threshold and when they did it. git blame pointed directly at Jamie Park's late-evening commit on June 10.

But knowing who and when is only half the picture. git show reveals the complete diff for a commit, including what was removed and what was added. That tells you the magnitude of the change.

In this step, get ready to:
  • Inspect the suspicious commit's full diff and commit message.
  • Compare it side-by-side with a legitimate tuning commit.
  • Use path filtering to isolate the file-specific diff.
View the full suspicious commit

git show takes a commit hash and displays the full commit message followed by the complete diff. This is how you see exactly what was added and removed in a single commit.

  • Copy the commit hash you noted from the git blame output in the previous step (the hash for Jamie Park's June 10 change).
  • View the full commit details by running this command:
git show [[SUSPICIOUS_HASH="the commit hash from git blame for Jamie's change"]]

What does this output show?

git show displays two things: the commit metadata (author, date, and message) followed by the full diff (lines removed shown with - and lines added shown with +).

Read through the output carefully. The commit message is just "Update exfiltration rule parameters". No ticket reference, no explanation of why the change was made.

In the diff, you can see two changes: the threshold went from > 50 to > 500, and a new false positive entry "End-of-quarter reporting" was added.

Compare with a legitimate tuning commit

A suspicious change only looks suspicious in contrast to what normal changes look like. You need a baseline for comparison.

  • Find the legitimate tuning commit by running this command:
git log --oneline -- rules/data-exfiltration/mass-file-download.yml
  • Copy the hash of the commit that says "Lower mass download threshold from 100 to 50 files".
  • Inspect that legitimate commit by running:
git show [[LEGITIMATE_HASH="the commit hash for 'Lower mass download threshold from 100 to 50 files'"]]

Notice the difference in quality. This commit has a detailed explanation, references incident SOC-4521, and mentions SOC lead approval for the expected false positive increase.

Why does this comparison matter?

The legitimate commit tells a complete story: an attacker exfiltrated 78 files without triggering the alert, so the team tightened the threshold from 100 to 50. It names the incident, explains the trade-off, and documents approval.

Jamie's commit does the opposite: it loosens the threshold by 10x with zero context. In a detection-as-code workflow, this contrast is a red flag.

Confirm the scope of the suspicious change

When investigating a commit, you also want to know how many files it touched. A commit that modifies a single rule file tells a different story than one that refactors many files at once.

  • View a summary of the files changed in Jamie's commit by running:
git show --stat [[SUSPICIOUS_HASH="the commit hash from git blame for Jamie's change"]]

What does --stat show?

The --stat flag shows a file-level summary of changes: which files were modified and how many lines were added or removed in each. It is useful for a quick scope check without reading the full diff.

You should see that only one file was modified: rules/data-exfiltration/mass-file-download.yml.

  • Now isolate the diff to just that specific file by running:
git show [[SUSPICIOUS_HASH="the commit hash from git blame for Jamie's change"]] -- rules/data-exfiltration/mass-file-download.yml

When is path filtering useful?

The -- <path> syntax after a commit hash limits the diff output to just that file. This is invaluable when a commit touches multiple files and you only care about one.

Before you look at the output, predict what you will see in the diff. Based on what you know so far, what lines do you expect were removed and what lines were added?

The diff shows > 50 changed to > 500 (a 10x weakening of the detection threshold) and "End-of-quarter reporting" added as a false positive. The commit message contains zero justification or ticket reference.

Not seeing the diff output?

Make sure you are using the correct commit hash from your git blame output (the one attributed to Jamie Park, dated June 10). You need at least the first 7 characters of the hash.

If the output is long and seems to pause, press Space to page forward or q to exit the pager.

Help me debug why git show isn't displaying the diff I expect.

You now have concrete evidence of what changed and how it compares to legitimate work. Next, you will search commit messages across the entire repository to determine whether this missing ticket reference violates the team's established norms.

Search Commit Messages for Patterns with git log --grep

In the previous step, you inspected Jamie's suspicious commit in full detail with git show. You now know the magnitude of the change (threshold raised 10x) and that it lacks any justification.

One unexplained commit could be a mistake. To determine whether it actually violates the team's norms, you need to see how every other commit handles ticket references and justifications. The --grep flag on git log lets you search commit messages for patterns, turning a hunch into hard evidence.

In this step, get ready to:
  • Search commit messages for SOC ticket references to establish the team's documentation norm.
  • Filter commits by author to check whether Jamie's suspicious commit is an outlier in their own work.
  • Search for tuning-related keywords to compare legitimate rule changes against the suspicious one.
Search for SOC ticket references with --grep

Every well-run detection engineering team references a ticket when they change a rule. If Jamie's commit is the only one missing a reference, that is a strong indicator something is wrong.

  • Find all commits that mention a SOC ticket by running this command:
git log --oneline --grep="SOC-"

You should see 9 commits listed, each with a SOC ticket number in the message.

What does --grep do?

The --grep flag filters git log output to only show commits whose message matches the pattern you provide. It uses regular expressions by default, but a simple string like SOC- works as a literal match.

Now you know what normal looks like. Before you run the next command, think about this: what would you expect to see when you ask Git to show commits that do NOT contain a ticket reference?

  • Find commits that are missing a ticket reference by running:
git log --oneline --grep="SOC-" --invert-grep

You see 2 commits without ticket references. One is the initial repository setup (which wouldn't need a ticket). The other is Jamie's "Update exfiltration rule parameters" from June 10. That is the only rule change in the entire repository that skips the team's documentation practice.

What does --invert-grep do?

The --invert-grep flag reverses the filter. Instead of showing commits that match the pattern, it shows commits that do NOT match. Combined with --grep="SOC-", it reveals every commit missing a ticket reference.

Check Jamie's commit history with --author

Finding one bad commit does not mean the author is always careless. You need to check whether this is a pattern in Jamie's work or an isolated anomaly.

  • View all of Jamie's commits in the repository by running:
git log --oneline --author="Jamie Park"

You see three commits by Jamie. Two of them (USB mass storage detection and VPN rule tuning) have clear ticket references and detailed justifications. Only the June 10 exfiltration change is missing these.

What does this tell you?

Jamie generally follows the team's documentation practices. The suspicious commit is not a sign of habitual sloppiness. It is an isolated departure from their normal behaviour, which makes it more noteworthy, not less.

Search for tuning-related commits

The suspicious commit claims to "update parameters," which is a type of rule tuning. If every other tuning commit explains business impact and references a specific incident, Jamie's commit stands out even more sharply.

  • Search for all commits related to tuning by running:
git log --oneline --grep="false positive\|FP\|threshold"

Every tuning commit in the results explains the business impact (alert volume, specific incident) and references a ticket. Jamie's "Update exfiltration rule parameters" commit stands alone as unexplained tuning.

How does this regex pattern work?

The \| syntax is the alternation (OR) operator in basic regular expressions. The pattern false positive\|FP\|threshold matches any commit message containing "false positive" OR "FP" OR "threshold".

Not seeing results from the regex search?

On some macOS versions, the \| alternation may not work in basic regular expressions. If you see no output, try using separate --grep flags instead:

git log --oneline --grep="false positive" --grep="FP" --grep="threshold"

When you supply multiple --grep patterns, Git shows commits matching any of them by default. This achieves the same OR logic without relying on regex alternation.

Help me search for multiple patterns in commit messages

You have now assembled a complete evidence trail. 9 out of 11 commits follow the team's ticket reference norm. Jamie's own work normally follows this norm. Every other tuning commit explains its reasoning.

The June 10 exfiltration rule change is the single exception across all three dimensions.

Secret mission

Conduct a Full Forensic Investigation

You have all the Git forensics techniques. Now combine them into a structured investigation workflow. Extract a clean timeline, correlate authors and dates, and write a formal investigation summary that could be handed to a security manager.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally with no cloud resources or paid services, so there are no ongoing costs.

Resources you used:

  • detection-rules-audit directory (local Git repository with rule files, commit history, and your investigation report).
  • setup-detection-repo.sh script (used to generate the repository).

Keep everything running

No action needed. Choose this if you want to keep practicing Git forensics commands or reference the detection rules and commit history later.

  • The detection-rules-audit repository stays on your Desktop for future reference.
  • You can re-run any of the git log, git blame, and git show commands to practice your investigation workflow.
  • Your investigation-report.md file is saved in the repo root if you want to refine it.

Pause - I'll come back to this later

Since this is a local Git repository with no running processes, there is nothing to pause. The files sit on disk and consume no memory or CPU when you are not using them.

  • Close VS Code and your terminal window.
  • The repository will be exactly where you left it when you return.

Delete - I don't want to use this again

Remove all project files from your machine. This deletes the Git repository, all rule files, and your investigation report permanently.

  • Navigate to the parent directory (your Desktop) by running:
cd ~/Desktop
  • Delete the repository and the setup script by running:
rm -rf detection-rules-audit
rm setup-detection-repo.sh
  • Confirm the files are gone by running:
ls
  • You should no longer see detection-rules-audit or setup-detection-repo.sh in the output.

Nice Work!

Nice Work!

You just conducted a full forensic investigation of a suspicious detection rule change using nothing but Git commands. You traced who weakened a critical exfiltration rule, when they did it, and built an evidence trail proving it violated team norms.

You've learned how to:

  • Build a detection rule investigation workflow using git log, git blame, git show, and git log --grep to trace changes across a detection-as-code repository.
  • Identify suspicious rule changes by cross-referencing commit metadata, diffs, and author patterns to pinpoint exactly who weakened a critical detection threshold and when.
  • Search commit messages for ticket reference patterns to establish team norms and flag changes that lack proper justification.
  • Conduct a full forensic investigation combining all techniques into a structured evidence trail with a written investigation report (Secret Mission).

Ready to quiz yourself?