launchd is macOS and Darwin’s service manager and init system, responsible for starting daemons, user agents, and jobs at boot or on demand. Attackers abuse its launch items for persistence. Defenders should inspect launch daemons and agents, verify ownership and permissions, and alert on new or modified jobs.
What launchd does on macOS and Darwin
launchd is the startup and service-management layer for macOS and Darwin. It starts system daemons, per-user agents, and one-off jobs at boot or when triggered by demand, so it acts as both init system and job scheduler. That design makes it central to how background services are launched, supervised, and restarted when they exit.
Because launchd is the entry point for so much background execution, it is not just a convenience layer, it is part of the system’s trust boundary. A legitimate launch item can be used to start approved services, but the same mechanism can also be abused to run attacker-controlled code whenever the system or a user session starts.
How launchd launch items are defined and triggered
launchd jobs are usually described in property list files, often called launch daemons or launch agents depending on whether they run system-wide or in a user context. Those definitions tell launchd what executable to start, under which account, and which conditions should trigger execution, such as boot, login, filesystem events, sockets, timers, or explicit requests.
That trigger model is what makes launchd flexible and also what makes it attractive for persistence. A job does not need to run constantly to be effective, because launchd can bring it to life only when the right condition appears. For defenders, the important detail is that a malicious job may look dormant until the next reboot, user logon, or trigger event.
Persistence Techniques Guide is the most useful internal reference here because launchd persistence is one example of broader autostart abuse, and the same detection mindset applies across platforms.
Why launchd is useful for persistence and what to check
Attackers favor launchd because it offers a native, trusted way to re-enter the system without introducing an obvious external service. If a launch item is planted in a writable location, points to an attacker-controlled binary, or is modified to point to a malicious payload, the system itself may faithfully execute it as part of normal startup behaviour.
That is why review should focus on ownership, file permissions, executable paths, signing where applicable, and whether the job matches an expected service role. New launch items are important, but so are small edits to existing ones, because a minor change in the plist can redirect execution while preserving a familiar filename or label.
Defenders should also compare active jobs against known-good baselines and alert on unusual paths, odd run intervals, hidden payload locations, and jobs created by unexpected users or processes. In practice, the strongest signal is often not just “a launch item exists,” but “this launch item changed in a way that gives a low-trust process durable execution.”
How to investigate suspicious launchd activity
When launchd abuse is suspected, the first task is to determine whether the launch item is expected, which account owns it, and what binary it invokes. Review the plist metadata, the referenced executable, and any supporting files for tampering, mismatched timestamps, or permission settings that would allow a non-administrative actor to alter persistence.
It also helps to separate persistence from privilege. A launch item can be malicious even if it runs under a normal user context, and a user-level agent can still provide long-term foothold, credential theft, or staging for later escalation. If the launch item points to a script or wrapper, inspect the entire chain, not just the plist itself, because the real payload may be one hop away.
For incident response, treat modified launch items as part of the compromised execution path, not as a standalone configuration issue. If the job has been used for persistence, remove the item, restore trusted configuration, and check whether the underlying executable, script, or parent process was also altered to survive cleanup.
Risk and Threat Considerations
launchd matters from a threat perspective because it turns a system management mechanism into a durable execution channel. If an attacker can write or modify a launch item, they can often survive reboots, blend in with normal service behaviour, and re-establish execution without dropping a visibly new service.
Failure mechanism: Weak file permissions, writable launch paths, or overly trusting service definitions let an attacker replace or redirect a launch item so launchd starts malicious code instead of the intended job.
Impact: The result can be persistent access, repeated code execution after reboot or logon, and a higher chance that the compromise survives routine cleanup unless launch items are explicitly reviewed and removed.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK addresses the attack and risk surface, while CIS Controls v8 and NIST SP 800-53 Rev 5 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| MITRE ATT&CK | T1543 — Create or Modify System Process | launchd jobs are a native startup persistence mechanism. |
| T1037 — Boot or Logon Initialization Scripts | launchd jobs execute at boot or logon-like events, making them persistence-relevant. | |
| Recommendation — Map launch items to T1543 and hunt for unauthorized startup persistence changes. Correlate launchd jobs with boot and user-session startup activity during persistence hunts. | ||
| CIS Controls v8 | CIS-4 — Secure Configuration of Enterprise Assets and Software | Launch items depend on secure service and file configuration on macOS hosts. |
| Recommendation — Enforce hardened baseline settings for launchd paths, ownership, and permissions. | ||
| NIST SP 800-53 Rev 5 | CM-2 — Baseline Configuration | launchd persistence is best managed by approved configuration baselines and drift detection. |
| CM-6 — Configuration Settings | launchd security depends on correct ownership, permissions, and execution settings. | |
| Recommendation — Maintain approved baselines for launch agents and daemons, then alert on drift. Restrict launchd configuration settings to approved owners, paths, and execution contexts. | ||
Practitioner Guidance
What to verify: Confirm the launch item owner, the file path, the executable it invokes, and whether the job is expected for that host or user. If the plist is present but the binary is unfamiliar, treat that as a stronger signal than the mere presence of a launch entry.
Common mistake: Teams often check only the obvious startup folder equivalents and miss edited launch items already trusted by the operating system. The higher-value review is to compare current launch definitions to a known-good inventory and look for small, durable changes rather than only brand-new files.
Practitioner takeaway: launchd is safe when its launch items are tightly owned and continuously reviewed; it becomes an attacker persistence mechanism when write access, path trust, or change detection are weak.