Skip to Content
OpenVAPTAlpha
Pre-release. Academic, non-commercial, source-available code built by AI Cybersecurity Engineers. Free for your own use, 100% at your own risk. This website collects no data. Read MoreRead Less
Pre-release. OpenVAPT has no Stable release yet. Every build is an Alpha, Beta or Release Candidate: it may be incomplete or wrong, so use it only on test machines, 100% at your own risk. See Release Channels
Academic, non-commercial, source-available code built by AI Cybersecurity Engineers. These are AI systems, not people or registered engineers. Free for your own personal or business use, on your own machines, 100% at your own risk. Not for sale. Not for providing services. This website collects no data. Read the Acknowledgements
Pre-release. OpenVAPT has no Stable release yet. Every build is an Alpha, Beta or Release Candidate: it may be incomplete or wrong, so use it only on test machines, 100% at your own risk. See Release Channels
Academic, non-commercial, source-available code built by AI Cybersecurity Engineers. These are AI systems, not people or registered engineers. Free for your own personal or business use, on your own machines, 100% at your own risk. Not for sale. Not for providing services. This website collects no data. Read the Acknowledgements
P11PractitionerAbout 25 minutes

Service Hardening With systemd

How systemd starts services, why most services should not run as root, and how a few unit settings contain a compromised application.

Read First: P1

You Will Be Able To

  • Read a systemd unit file and its drop-ins and know which settings win.
  • Explain why a service's user, program location and unit file permissions decide what an attacker gains.
  • Apply basic sandboxing settings and keep secrets out of unit files.

How a Service Starts

systemd reads a service's unit file from /usr/lib/systemd/system or /lib/systemd/system (packages) or /etc/systemd/system (the administrator), then applies drop-in files from <name>.service.d/*.conf in order. A drop-in therefore overrides the unit file it extends. ExecStart= names the program, User= the account it runs as. With no User= the service runs as root.

Application services written by administrators, such as a Node.js API or a Django site, are the code most exposed to the internet. Running them as root turns any bug in the application into full control of the machine.

Who Can Change What Runs

A service is only as trustworthy as the files that define it. Suppose a normal user can edit the unit file, or replace the program it starts, such as a binary in /tmp or a world-writable file. That user can make systemd run their code as root at the next restart. This is a well-known privilege escalation and persistence technique (MITRE ATT&CK T1543.002 and T1574.010).

Sandboxing in a Few Lines

systemd can confine a service without changing its code. NoNewPrivileges=yes stops it gaining privileges through setuid programs. ProtectSystem=strict mounts the operating system read-only for it. PrivateTmp=yes gives it its own /tmp. ProtectHome=yes hides home directories. ReadWritePaths= then lists the few folders it really needs to write. systemd-analyze security <unit> scores how exposed a unit is and suggests more options.

Secrets Do Not Belong in Unit Files

Unit files are readable by every user, and systemctl show prints a service's Environment= values to anyone. Passwords and tokens belong in a root-only EnvironmentFile= or, better, in systemd credentials (LoadCredential=), which only the service can read.

In Summary

A systemd unit can run a service as a dedicated user inside a sandbox. Each hardening option removes something an attacker could abuse.

Apply It

These OpenVAPT checks put this module into practice. Open one to see its detection logic and source code.

Printable Worksheet · Teacher Answer Key · For Teachers · Print this page with your browser's Print command for a handout.

Also available as plain Markdown for notes, scripts and AI tools. Same facts, same source, no styling.

Lab

  1. Run: openvapt demo --only HOST-SYSD- --out p11 and list, for each vulnerable unit, the line you would add or change.
  2. Compare the shop-api.service unit in the vulnerable and hardened labs (internal/lab/fixtures_stacks.go) setting by setting.
  3. On a test machine: systemd-analyze security and pick the service with the worst score; add NoNewPrivileges=yes with systemctl edit and re-run.

Check Yourself

Answers are checked in your browser and never stored or sent.

Question 1

1. A system service unit has no User= line. Which account runs the service?

Question 2

2. Why is a world-writable unit file dangerous?

Question 3

3. Where should a service's database password go?

Question 4

4. What does ProtectSystem=strict do?

Question 5

5. A unit file and a drop-in in <name>.service.d/ set the same option differently. Which value normally applies?

Question 6

6. Which command scores how exposed a unit is?

References

Cite This Page

If this page helped your work, please cite it. The version and web address are filled in; the access date is today's date in your browser. Every other style, and when credit is required, is on How to Cite OpenVAPT.

APA 7
OpenVAPT. (2026). P11: Service Hardening With systemd (Version 0.1.0-alpha.6). OpenVAPT Academy. Retrieved October 16, 2026, from https://openvapt.com/academy/p11.html

In text: (OpenVAPT, 2026). Accessed: the date shown is today's date from your own browser (the site's build date without JavaScript); change it to the day you read the page.

BibTeX
@misc{openvapt_p11,
  author       = {{OpenVAPT}},
  title        = {{P11: Service Hardening With systemd}},
  year         = {2026},
  howpublished = {\url{https://openvapt.com/academy/p11.html}},
  note         = {OpenVAPT Academy, version 0.1.0-alpha.6. Accessed 16 October 2026}
}

Accessed: the date shown is today's date from your own browser (the site's build date without JavaScript); change it to the day you read the page.

Citing OpenVAPT does not mean OpenVAPT endorses, approves or has reviewed your work.