How to Audit macOS LaunchAgents and Background Processes for Suspicious Activity
A Mac that has run fine for months can pick up a new background item without you noticing. A free app or a pop-up installer drops it in, and the clues are a loud fan or a battery that dies early. This is the hands-on pass: which jobs start by themselves.
Why background items matter
Spotlight indexes files, iCloud uploads photos, and an updater you have not opened in months still checks in. launchd starts them. launchctl list shows the jobs loaded for your user. A dash in the first column means loaded and waiting. A number means it is running. On this Mac, Zoom and Google’s updater were idle, and Microsoft AutoUpdate was running:
greys@macos $ launchctl list | grep -E 'zoom.updater$|microsoft.update.agent|GoogleUpdater.wake'
- 0 us.zoom.updater
97185 0 com.microsoft.update.agent
- 0 com.google.GoogleUpdater.wakeMalware wants the same arrangement, because a program you have to open by hand is gone after the next restart. Gatekeeper and XProtect are the built-in protections. Can you do better? You sure can. One good example is Moonlock, which provides layered protection against evolving threats: real-time checks on new files and app behavior, an on-demand malware scan, and extra cover for network traffic and phishing.
How LaunchAgents work
launchd reads plist files. A LaunchAgent starts when you log in. A LaunchDaemon starts at boot and runs as root. Zoom’s updater on this Mac is a normal one. RunAtLoad and KeepAlive are both false, and StartCalendarInterval wakes it twice a day:
greys@macos $ plutil -p /Library/LaunchAgents/us.zoom.updater.plist
{
"AssociatedBundleIdentifiers" => [
0 => "us.zoom.xos"
]
"KeepAlive" => false
"Label" => "us.zoom.updater"
"ProgramArguments" => [
0 => "/Applications/zoom.us.app/Contents/Library/LaunchAgents/ZoomUpdater.app/Contents/MacOS/ZoomUpdater"
1 => "--update"
]
"RunAtLoad" => false
"StartCalendarInterval" => [
0 => {
"Hour" => 3
"Minute" => 23
}
1 => {
"Hour" => 15
"Minute" => 23
}
]
}ProgramArguments is the program. Label is the name in launchctl. RunAtLoad starts it at login. KeepAlive starts it again whenever it quits. Real software uses those keys, and so does malware. The check is whether the label and the path belong together.
Where they are stored
There are four places to look:
~/Library/LaunchAgentsis yours. Writing there does not need an admin password, so start here./Library/LaunchAgentsis shared by every user on the Mac./Library/LaunchDaemonsruns at boot, as root./System/Librarybelongs to Apple. Leave those plists alone.
Finder hides your Library. Click Go, hold Option, and it appears. Open a plist in TextEdit and read ProgramArguments.
What normal looks like
Most of what you find is fine. The filename is a domain written backwards, then the job: us.zoom.updater.plist, com.microsoft.update.agent.plist, com.google.GoogleUpdater.wake. The path should sit inside that company’s app. On this Mac, com.google.keystone.agent.plist is empty. The Google job launchctl has loaded is com.google.GoogleUpdater.wake.
mdworker at the top of Activity Monitor is Spotlight. When files change, it reads them so search can catch up, which is why a macOS update or a large copy keeps it busy. The real binary lives in Metadata.framework. If it has stayed at the top for a day, or the path is outside a system folder, look again.
Checking the signature
In Activity Monitor, sort by CPU and double-click a process. The window shows the path and open files. bird is a good one to practice on. It is iCloud Drive sync, so it spikes when a large folder uploads, and on this Mac it lives under iCloudDriveCore.framework. codesign -dvvv says who signed that file. Apple’s own software chains to Apple:
greys@macos $ codesign -dvvv /System/Library/PrivateFrameworks/iCloudDriveCore.framework/Versions/A/Support/bird 2>&1 | grep Authority
Authority=macOS Software Signing
Authority=Apple Code Signing Certification Authority
Authority=Apple Root CAA program with no signature, sitting in your user folder, is the one to follow up on.
Spotting suspicious behavior
One odd detail means little. Three or four together are worth acting on. Zoom’s label and path, shown above, name the same product. The rows below are the opposite, and they are made up. Nothing in this table was installed on the Mac used for the real examples. The labels, paths, and hostnames show how a bad job looks. They are not names of specific malware.
| Pattern | Invented example | Why it is wrong |
|---|---|---|
| An Apple name in your own Library | ~/Library/LaunchAgents/com.apple.sysupdate.plist launches ~/Library/Application Support/.helper/update | Apple’s agents live under /System/Library and codesign as Apple. A com.apple label in a user folder is a borrowed name. |
| The label and the program disagree | Label com.google.chrome.helper, program ~/Library/Caches/agent | The loaded Google job on this Mac is com.google.GoogleUpdater.wake, inside Google’s app. This label names Google and the path is a cache folder. |
| The program sits in a temporary or hidden directory | RunAtLoad is true and the program is /tmp/.update/helper | Installers use /tmp and then leave. A login job that stays there, in a dot-directory, has no vendor path you can recognize. |
RunAtLoad and KeepAlive are both set on a stranger | Label com.adobe.sync.helper, both keys true, program ~/Library/Application Support/AdobeSync/sync | Zoom’s real agent sets both keys to false. This one starts at login, comes back whenever it quits, and the folder name only resembles Adobe. |
| A familiar process name with the wrong path | Activity Monitor shows mdworker busy while the Mac is idle, path ~/Library/Application Support/mdworker | The real mdworker lives in Metadata.framework. The name matches Spotlight. The path and the idle CPU do not. |
| A network connection you cannot place | lsof on that process shows a connection to updates.example.net | example.net is a documentation domain, so this row is obviously fake. A real miss is a host that does not belong to the company in the label. |
System Settings has the same list under General, then Login Items, in Allow in the Background. macOS posts a notification when a new item is added.
If you decide to remove one
Write down the plist path, quit the process in Activity Monitor, then unload the job. Use your file in place of the example. This command was not run here:
greys@macos $ launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.example.agent.plist$(id -u) is your user id, 501 on this Mac. Delete the plist and the program ProgramArguments points at, then restart and look again. Some malware puts the files back. A scanner is a second opinion: get it from the developer’s own site, because search ads for these tools sometimes lead to fakes, and compare what it flags with the plists you just read. If that Mac was used for banking or work, change those passwords from another device, including the Apple ID.
Most of the time you will find an old updater from an app you deleted. Once a month is plenty.






