// question

On a Linux system you suspect someone altered Bash’s history settings to hide their activity. Investigate process logs for evidence of HISTCONTROL being set to ignore entries. What was the full command executed to configure HISTCONTROL?

Reference KQL answer and model-by-model comparison.

10ab786a-028e-4465-96f6-9e83ca6c5f24
question id
19/23
models correct
1
valid answer
83%
success rate
// reference answer

Human-validated correct answer for this question.

export HISTCONTROL="ignoreboth"
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
export HISTCONTROL=ignoreboth
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine contains "HISTCONTROL="
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
pass19.87s0.0039
gpt-35-turbo
export HISTCONTROL=ignoreboth
DeviceProcessEvents | where ProcessCommandLine contains 'HISTCONTROL=' | project ProcessCommandLine, ProcessCreationTime, DeviceName, DeviceId
pass17.64s0.0040
gpt-4-turbo-2024-04-09
bash -c 'TEST=$(echo $HISTCONTROL); if [ "$HISTCONTROL" != "ignoreboth" ]; then export HISTCONTROL="ignoreboth"; fi; history -c ; ls -la $HISTFILE # " ls -la $HISTFILE"; if [ $(history |wc -l) -eq 1 ]; then echo "ls -la is not in history cache"; fi; if [ "$HISTCONTROL" != "erasedups" ]; then export HISTCONTROL="erasedups"; fi; history -c ; ls -la $HISTFILE; ls -la $HISTFILE; ls -la $HISTFILE; if [ $(history |wc -l) -eq 2 ]; then echo "Their is only one entry for ls -la $HISTFILE"; fi'
DeviceProcessEvents
| where ProcessCommandLine contains 'HISTCONTROL'
| where ProcessCommandLine has 'ignorespace' or ProcessCommandLine has 'ignoredups' or ProcessCommandLine has 'ignoreboth' or ProcessCommandLine has 'ignoreshistory'
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
| distinct TimeGenerated, DeviceName, AccountName, ProcessCommandLine
pass115.75s0.0635
gpt-4.1
sh -c "export HISTCONTROL=ignoreboth; whoami"
DeviceProcessEvents
| where ProcessCommandLine has "HISTCONTROL="
    and (ProcessCommandLine has "ignore" or ProcessCommandLine matches regex @"HISTCONTROL\s*=\s*ignore")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessCommandLine, FolderPath
| order by TimeGenerated desc
pass14.14s0.0115
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0470
gpt-4.1-mini
sh -c "export HISTCONTROL=ignoreboth; whoami"
DeviceProcessEvents
| where InitiatingProcessCommandLine contains_cs "HISTCONTROL=ignore"
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine
| order by TimeGenerated desc
pass12.83s0.0022
gpt-4.1-nano
export HISTCONTROL=ignoreboth
DeviceProcessEvents | where ProcessCommandLine contains 'HISTCONTROL' and ProcessCommandLine contains 'ignore' | project TimeGenerated, InitiatingProcessFileName, ProcessCommandLine, DeviceName | order by TimeGenerated desc
pass12.18s0.0006
gpt-4o
sh -c "export HISTCONTROL=ignoreboth; whoami"
DeviceProcessEvents
| where ProcessCommandLine contains "HISTCONTROL"
| project TimeGenerated, InitiatingProcessAccountName, DeviceName, ProcessCommandLine, InitiatingProcessFolderPath
pass12.57s0.0155
gpt-5-high
sh -c "export HISTCONTROL=ignoreboth; whoami"
let LinuxDevices = DeviceInfo
| where OSPlatform =~ "Linux"
| project DeviceId, DeviceName, MachineGroup;
DeviceProcessEvents
| join kind=inner (LinuxDevices) on DeviceId
| where ActionType == "ProcessCreated"
| where isnotempty(ProcessCommandLine)
| where ProcessCommandLine has "HISTCONTROL"
      and ProcessCommandLine has_any ("ignoreboth","ignorespace","ignoredups","erasedups")
| extend HistControlSetting = tostring(extract(@'HISTCONTROL\s*=\s*["'']?([^"'';|&\s]+)', 1, ProcessCommandLine))
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessAccountName,
          FullCommand = ProcessCommandLine, HistControlSetting,
          FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by TimeGenerated desc
pass2162.51s0.1022
gpt-5-mini-high
HISTCONTROL=ignoreboth
union DeviceProcessEvents, DeviceEvents, DeviceFileEvents
| extend ProcessCommandLine = tostring(ProcessCommandLine), InitiatingProcessCommandLine = tostring(InitiatingProcessCommandLine), AdditionalFields = tostring(AdditionalFields)
// Keep only rows that contain HISTCONTROL somewhere (case-insensitive)
| where tolower(ProcessCommandLine) contains "histcontrol" or tolower(InitiatingProcessCommandLine) contains "histcontrol" or tolower(AdditionalFields) contains "histcontrol"
// Choose the best available command/text to inspect
| extend MatchedCommand = coalesce(ProcessCommandLine, InitiatingProcessCommandLine, AdditionalFields)
// Extract the assigned value and the full assignment (case-insensitive)
| extend AssignedValue = extract("(?i)HISTCONTROL\\s*=\\s*['\\\"]?([^;\\'\\\"\\s]+)", 1, MatchedCommand)
| extend FullAssignment = extract("(?i)(HISTCONTROL\\s*=\\s*['\\\"]?[^;\\'\\\"\\s]+)", 1, MatchedCommand)
// Narrow to ignore-like assignments
| where AssignedValue != "" and tolower(AssignedValue) contains "ignore"
| project TimeGenerated, DeviceName, AccountName = coalesce(AccountName, InitiatingProcessAccountName), InitiatingProcessAccountName, ProcessId, InitiatingProcessId, InitiatingProcessFileName, FileName, FolderPath, MatchedCommand, FullAssignment, AssignedValue
| order by TimeGenerated desc
| take 50
fail247.63s0.0122
gpt-5-mini-low
sh -c "export HISTCONTROL=ignoreboth; whoami"
let shell_names = dynamic(['bash','sh','dash','zsh','ksh']);
// Search DeviceProcessEvents (Linux process telemetry) for commands setting HISTCONTROL
DeviceProcessEvents
| where Timestamp between (startofday(ago(30d)) .. now())
// filter to likely shell processes or commands invoked via sudo
| where tolower(FileName) in (shell_names) or tolower(ProcessCommandLine) has_any ("bash","sh","export HISTCONTROL","HISTCONTROL=","HISTCONTROL ")
| where ProcessCommandLine has "HISTCONTROL" or InitiatingProcessCommandLine has "HISTCONTROL" or ProcessCommandLine has_cs "HISTCONTROL=" or InitiatingProcessCommandLine has_cs "HISTCONTROL="
| extend Cmd = coalesce(ProcessCommandLine, InitiatingProcessCommandLine)
| extend User = coalesce(AccountName, InitiatingProcessAccountName, AccountUpn)
| extend Process = FileName
| project Timestamp, DeviceName, DeviceId, User, Process, ProcessId, ProcessCreationTime, Cmd
| union (
    // Also check DeviceEvents (some agents log shell or command exec here)
    DeviceEvents
    | where Timestamp between (startofday(ago(30d)) .. now())
    | where tolower(FileName) in (shell_names) or tolower(ProcessCommandLine) has_any ("bash","sh","export HISTCONTROL","HISTCONTROL=","HISTCONTROL ")
    | where ProcessCommandLine has "HISTCONTROL" or InitiatingProcessCommandLine has "HISTCONTROL" or ProcessCommandLine has_cs "HISTCONTROL=" or InitiatingProcessCommandLine has_cs "HISTCONTROL="
    | extend Cmd = coalesce(ProcessCommandLine, InitiatingProcessCommandLine)
    | extend User = coalesce(AccountName, InitiatingProcessAccountName, InitiatingProcessAccountUpn)
    | extend Process = FileName
    | project Timestamp, DeviceName, DeviceId, User, Process, InitiatingProcessId, ProcessCreationTime, Cmd
)
| order by Timestamp desc
| distinct Timestamp, DeviceName, DeviceId, User, Process, ProcessId, ProcessCreationTime, Cmd
| take 100
pass122.82s0.0050
gpt-5-mini-medium
no answer
no query generatedfail50.00s0.0175
gpt-5-nano-high
bash -c 'TEST=$(echo $HISTCONTROL); if [ "$HISTCONTROL" != "ignoreboth" ]; then export HISTCONTROL="ignoreboth"; fi; history -c ; ls -la $HISTFILE # " ls -la $HISTFILE"; if [ $(history |wc -l) -eq 1 ]; then echo "ls -la is not in history cache"; fi; if [ "$HISTCONTROL" != "erasedups" ]; then export HISTCONTROL="erasedups"; fi; history -c ; ls -la $HISTFILE; ls -la $HISTFILE; ls -la $HISTFILE; if [ $(history |wc -l) -eq 2 ]; then echo "Their is only one entry for ls -la $HISTFILE"; fi'
DeviceProcessEvents
| where (tolower(InitiatingProcessFileName) contains "bash" or tolower(ProcessCommandLine) contains "bash")
| where (
    tolower(InitiatingProcessCommandLine) contains "histcontrol" or
    tolower(ProcessCommandLine) contains "histcontrol" or
    tolower(InitiatingProcessCommandLine) contains "export histcontrol" or
    tolower(InitiatingProcessCommandLine) contains "histcontrol=" or
    tolower(ProcessCommandLine) contains "histcontrol="
  )
| project TimeGenerated, DeviceName, DeviceId, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessAccountName, InitiatingProcessAccountDomain, InitiatingProcessCommandLine, ProcessCommandLine
| sort by TimeGenerated desc
pass156.53s0.0035
gpt-5-nano-medium
sh -c "export HISTCONTROL=ignoreboth; whoami"
let _StartTime = ago(7d);
DeviceProcessEvents
| where TimeGenerated >= _StartTime
| where InitiatingProcessFileName in ('bash','sh') or InitiatingProcessCommandLine contains 'HISTCONTROL'
| extend HistControlValue = extract(@'(?i)(?:export\s+)?HISTCONTROL\s*=\s*([^;\s]+)', 1, InitiatingProcessCommandLine)
| where isnotempty(HistControlValue)
| where tolower(HistControlValue) in ('ignoreboth','ignorespace','ignoredups')
| project TimeGenerated, InitiatingProcessCreationTime, DeviceName, InitiatingProcessAccountName, InitiatingProcessId, InitiatingProcessCommandLine, HistControlValue
| sort by TimeGenerated desc
pass3104.55s0.0049
grok-3-beta
export HISTCONTROL="ignoreboth"
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName contains "bash" or ProcessCommandLine contains "bash"
| where ProcessCommandLine contains "HISTCONTROL" or InitiatingProcessCommandLine contains "HISTCONTROL"
| where ProcessCommandLine contains "ignorespace" or ProcessCommandLine contains "ignoreboth" or InitiatingProcessCommandLine contains "ignorespace" or InitiatingProcessCommandLine contains "ignoreboth"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessCommandLine, ProcessCreationTime
| order by Timestamp desc
pass121.08s0.0245
grok-3-mini-beta
export HISTCONTROL=ignoreboth
DeviceProcessEvents
| where ProcessCommandLine contains "HISTCONTROL"
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
| order by TimeGenerated desc
pass116.28s0.0017
o1-high
sh -c "export HISTCONTROL=ignoreboth; whoami"
DeviceProcessEvents
| join kind=inner DeviceInfo on DeviceId
| where OSPlatform == "Linux"
| where ProcessCommandLine has "HISTCONTROL="
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
| order by TimeGenerated desc
pass255.16s0.4430
o1-low
sh -c "export HISTCONTROL=ignoreboth; whoami"
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where tolower(ProcessCommandLine) has "histcontrol"
| join kind=leftsemi (
    DeviceInfo
    | where OSPlatform == "Linux"
) on DeviceId
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
| order by TimeGenerated desc
pass145.28s0.3239
o3-high
sh
// Identify Linux endpoints first so we do not get false-positives from Windows PowerShell history variables
let LinuxDevices = DeviceInfo
    | where OSPlatform == "Linux"
    | project DeviceId, DeviceName;

// Look for processes that changed the HISTCONTROL variable to a value that suppresses entries (ignore*, ignoredups, ignorespace, ignoreboth)
DeviceProcessEvents
| where DeviceId in (LinuxDevices)                                   // keep only events coming from Linux machines
| where ActionType == "ProcessCreated"                               // normal process start events
// Focus on interactive shells or any command-line where HISTCONTROL was manipulated
| where FileName in~ ("bash","sh","dash","zsh","ksh","sudo")
      or ProcessCommandLine has_any ("export HISTCONTROL", "HISTCONTROL=")
// Normalise for case and white spaces
| extend cmd_lower = tolower(ProcessCommandLine)
| where cmd_lower has "histcontrol="                      // the variable assignment must be present
      and cmd_lower matches regex @"ignore[a-z]*"          // value contains the word "ignore" (ignore, ignoredups, ignorespace, ignoreboth …)
// Return the interesting details – the full command shows exactly how HISTCONTROL was configured
| project TimeGenerated,
          DeviceName,
          AccountName,
          FileName,
          ProcessCommandLine,                    // full command that performed the change – answers the investigation question
          InitiatingProcessCommandLine,
          InitiatingProcessAccountName,
          ProcessId,
          InitiatingProcessId
| order by TimeGenerated desc
fail294.48s0.0450
o3-mini-high
ignoreboth
DeviceProcessEvents
| where ProcessCommandLine contains "HISTCONTROL" and ProcessCommandLine contains "="
| project ProcessCreationTime, DeviceName, AccountName, ProcessCommandLine
| order by ProcessCreationTime desc
pass1137.95s0.0166
o3-mini-low
ignoreboth

DeviceProcessEvents
| where isnotempty(ProcessCommandLine)
| where ProcessCommandLine contains "export HISTCONTROL" and ProcessCommandLine contains "ignore"
| project TimeGenerated, DeviceName, ProcessCommandLine
| order by TimeGenerated desc
pass223.09s0.0210
o4-mini-high
bash -c 'TEST=$(echo $HISTCONTROL); if [ "$HISTCONTROL" != "ignoreboth" ]; then export HISTCONTROL="ignoreboth"; fi; history -c ; ls -la $HISTFILE # " ls -la $HISTFILE"; if [ $(history |wc -l) -eq 1 ]; then echo "ls -la is not in history cache"; fi; if [ "$HISTCONTROL" != "erasedups" ]; then export HISTCONTROL="erasedups"; fi; history -c ; ls -la $HISTFILE; ls -la $HISTFILE; ls -la $HISTFILE; if [ $(history |wc -l) -eq 2 ]; then echo "Their is only one entry for ls -la $HISTFILE"; fi'
DeviceProcessEvents
| where FileName endswith "bash"
| where ProcessCommandLine contains "HISTCONTROL="
| sort by TimeGenerated desc
| project TimeGenerated, DeviceName, AccountName = InitiatingProcessAccountName, ProcessCommandLine
pass146.50s0.0142
o4-mini-low
sh -c "export HISTCONTROL=ignoreboth; whoami"
// Find processes that set HISTCONTROL to ignore on Linux devices
let linuxDevices = DeviceInfo
  | where tolower(OSPlatform) contains "linux"
  | project DeviceId;
DeviceProcessEvents
| where DeviceId in (linuxDevices)
// Look for any mention of HISTCONTROL being set to an ignore* value
| where tolower(ProcessCommandLine) contains "histcontrol"
  and tolower(ProcessCommandLine) contains "ignore"
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, ProcessCommandLine
| order by TimeGenerated desc
pass131.20s0.0129