Log Dejargonizer

Linux Audit Framework · Event EXECVE

auditd EXECVE: a command was executed

The Linux audit framework recorded a program being run, with every argument. Unlike sudo logging it works at the kernel level, so it keeps recording after someone obtains a root shell — which is precisely where sudo's audit trail ends.

Also written as type=EXECVEauditd execveaudit.log execvelinux command execution logging

What it means for you

On a personal computer

Not something a desktop Linux machine records by default. It is a server auditing feature.

For an analyst

An EXECVE record never stands alone — it is one line of a multi-line event joined by a shared event ID, with the SYSCALL record carrying the user identity and the CWD and PATH records carrying context. Tools like ausearch reassemble them; reading raw audit.log line by line will mislead you. Note that auid, the original login user, survives su and sudo, which is what makes attribution possible at all.

What it looks like

Sanitised. Addresses come from the RFC 5737 documentation ranges.

Sample
type=SYSCALL msg=audit(1756374000.123:45678): arch=c000003e syscall=59 success=yes exit=0 a0=55d1f2a3b4c0 a1=55d1f2a3b500 a2=55d1f2a3b560 items=2 ppid=24901 pid=25012 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=42 comm="curl" exe="/usr/bin/curl" key="user_commands"
type=EXECVE msg=audit(1756374000.123:45678): argc=4 a0="curl" a1="-s" a2="-o" a3="/tmp/x"
type=CWD msg=audit(1756374000.123:45678): cwd="/home/jbrooks"
type=PATH msg=audit(1756374000.123:45678): item=0 name="/usr/bin/curl" inode=1180 dev=fd:00 mode=0100755 ouid=0 ogid=0

The fields that decide it

Everything else in the log line is context.

argc
How many arguments the command had.
a0, a1, a2...
The arguments themselves, in order. a0 is the program. Long or unusual arguments are frequently hex-encoded rather than written as plain text.
auid
The original login user ID, carried in the accompanying SYSCALL record. It survives su and sudo, which makes it the only reliable attribution field.
  • 4294967295No login user — the process came from a system service rather than a person.
uid / euid
The user the process actually runs as, which is what the account became rather than who they logged in as.
key
The tag from the audit rule that matched. Set one on every rule or you will not know why a record was captured.
msg=audit(...)
The timestamp and a unique event identifier. All records sharing that identifier belong to one event and must be read together.

Ordinary reasons this happens

Most of the time it is one of these.

  • Every command run on the system, which is an enormous volume on a busy host.
  • System services and timers executing routine work.
  • Configuration management and deployment tooling.
  • Package management and update processes.
  • Monitoring agents running collection commands on a schedule.

When it is not ordinary

Commands run inside a root shell that sudo cannot log.

What gives it awayExecution recorded with uid 0 but an auid identifying a real user, after a su or sudo shell.

ATT&CK T1059.004

Reconnaissance after gaining a foothold.

What gives it awayA rapid sequence of enumeration commands from one session, faster than a person types.

ATT&CK T1082

Downloading tooling onto the host.

What gives it awaycurl, wget, or similar with an argument pointing at an unexpected host, particularly writing to a temporary directory.

ATT&CK T1105

Clearing shell history or logs.

What gives it awayCommands truncating history files or removing log files.

ATT&CK T1070.003

Commands encoded to evade simple matching.

What gives it awayArguments passed through base64 or built from concatenated strings, which is why hex-encoded arguments deserve decoding rather than skipping.

ATT&CK T1027

What to do next

  1. Use ausearch to reassemble the full event rather than reading raw lines — a bare EXECVE line has no user attribution at all.
  2. Read auid from the SYSCALL record. That is who logged in, regardless of what they became.
  3. Decode any hex-encoded arguments before judging the command.
  4. Read the rule key to understand why the record was captured.
  5. Look at what ran immediately before and after in the same session.
  6. Compare against the same user's normal command pattern before treating anything as unusual.

Queries to run

grep The correct way to read these. ausearch joins the multi-line records and the -i flag resolves numeric IDs to names.
ausearch -m EXECVE -ts today -i | less
grep Commonly abused commands. Expect legitimate hits — this is a starting point, not a rule.
ausearch -m EXECVE -ts recent -i | grep -E 'curl|wget|nc |base64|chmod \+x'
grep The rule that captures command execution by real users while excluding system accounts. Put it in /etc/audit/rules.d to persist it.
auditctl -a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k user_commands
grep Everything a specific login user ran today, regardless of what account they escalated to.
ausearch -ua 1000 -ts today -i | grep -A2 EXECVE
elastic
event.module:"auditd" and auditd.data.syscall:"execve" | stats count by process.args, user.name

Common questions

How do I log every command run on a Linux server?

Add an auditd rule on the execve syscall: `-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k user_commands`, placed in a file under /etc/audit/rules.d so it persists. That captures execution at the kernel level, which is the only approach that survives a user obtaining a root shell. Shell history is not a substitute — it is user-writable and easily cleared.

Why does the EXECVE record not show which user ran the command?

Because a single audit event is split across several record types, and the user identity lives in the accompanying SYSCALL record rather than in EXECVE. They share an event ID in the msg=audit() field. Use `ausearch` to reassemble them; reading audit.log line by line loses the attribution entirely.

What is auid in auditd and why does it matter?

The audit user ID — the account that originally logged in. It is set at login and does not change when the user runs su or sudo, so it still identifies the person even when uid has become 0. It is the only field that reliably answers 'who did this' after privilege escalation. A value of 4294967295 means there was no login user, indicating a system process.

Why are auditd command arguments sometimes shown as hex?

Because auditd hex-encodes any argument containing spaces, quotes, or non-printable characters, to keep the log format unambiguous. `ausearch -i` decodes them automatically. Grepping raw audit.log for a string will silently miss every encoded occurrence, which is a common reason searches come back empty when they should not.

Does auditd slow down a Linux server?

It can, and how much depends entirely on your rules. A rule capturing every execve on a busy machine generates very large volumes and measurable overhead. Scope rules with auid filters to exclude system accounts, avoid auditing high-frequency syscalls you do not need, and test on something representative before deploying widely.

Read next

Mentioned by

Vendor documentation

Last reviewed 28 August 2026