Join our Newsletter — 33% off our NHI Course
Home› Guides› OpenBSD Security: pledge, unveil, pf and a Hardening…
Guide Endpoint Security

OpenBSD Security: pledge, unveil, pf and a Hardening Baseline

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 8 November 2026 13 min read
On this page

OpenBSD's reputation for being "secure by default" leads some teams to deploy it as a firewall or bastion and then never touch it again, yet the defaults only cover what the project ships: the default pf ruleset passes traffic, only the two most recent releases get security fixes, and every service, doas rule and SSH key an administrator adds is outside the project's guarantee. This guide explains what OpenBSD actually does for you (code auditing, exploit mitigations, privilege separation, pledge and unveil) and what you still have to do: privileged access with doas, pf policy, patching with syspatch, securelevel, logging and the daily security report. It is for administrators and security engineers running OpenBSD as firewalls, routers, VPN gateways, jump hosts, mail or web servers. Facts are from the OpenBSD project's own pages and manual pages, checked 8 November 2026, when OpenBSD 8.0 (released 20 October 2026) and 7.9 were the supported releases. Compare the approach with the FreeBSD Security Hardening Guide.

This is an independent guide from NHI Mgmt Group, based on the OpenBSD project's public documentation as of November 2026. It is not sponsored or reviewed by the OpenBSD project. Product features change, so confirm settings against the OpenBSD project's current documentation.

Key takeaways

  • Secure by default means few services, not a locked firewall. OpenBSD disables all non-essential services, but the shipped /etc/pf.conf ends in pass; write a default-deny policy yourself.
  • Stay on a supported release. Only the two most recent releases receive base-system security and reliability fixes; a new release appears roughly every six months, so an untouched box falls out of support within about a year.
  • pledge and unveil shrink what a compromised program can do. pledge limits system calls to declared promise groups and kills the process on violation; unveil hides the filesystem except named paths. Base daemons use them; your own software should too.
  • doas is the privilege boundary. Rules are evaluated last-match-wins and deny by default; scope them to a group, a target user and an absolute command path.
  • Use the built-in evidence. The daily security(8) report, pf logging, authlog and lastcomm flags for pledge and unveil violations give detection without extra agents.

How identity and access work in OpenBSD

OpenBSD uses classic Unix identities: users and groups in /etc/master.passwd and /etc/group, with password hashes using bcrypt (an OpenBSD innovation). Base daemons run under dedicated unprivileged users (prefixed with an underscore, such as the _pbuild user the default pf ruleset blocks from the network) and many use privilege separation, splitting a small privileged parent from an unprivileged, chrooted worker.

IdentityWhere it is definedRiskControl
rootmaster.passwdFull control; can lower security unless securelevel blocks itNo direct SSH login with password (sshd default is prohibit-password; set no), use doas, raise securelevel
wheel group members/etc/groupThe sample doas.conf permits all of wheel with keepenvReplace the sample with scoped rules; keep wheel small
Daemon users (_name)Created by base and packagesCompromise of a daemon gives its user and filesPrivilege separation, pledge, unveil, chroot; pf user rules for egress
Automation and service accountsLocal users with SSH keysLong-lived keys with doas nopassOne user per job, forced commands, doas rule per command; see the SSH Key Management Guide
Human administratorsLocal users, SSH keysShared accounts, stale keysNamed accounts, key or certificate login, regular key review

The daily security report checks master.passwd and group for syntax errors, empty passwords, suspicious UIDs and GIDs and duplicate entries, checks root's dotfiles and home directory, and flags .rhosts and .shosts files. It runs from daily(8) and mails root, so make sure root's mail is forwarded to a monitored mailbox.

Admin roles and privileged access

OpenBSD ships doas(1) as its privilege escalation tool. A doas.conf rule has the form permit|deny [options] identity [as target] [cmd command [args ...]]. The last matching rule determines the action, and if no rule matches, the request is denied.

doas optionEffectGuidance
nopassNo password requiredOnly for a single, absolute-path command used by automation
persistDoes not ask for the password again for some time after authenticationAcceptable for interactive admins; avoid on shared or exposed hosts
nologDo not log successful execution to syslogdAvoid: removes your audit trail
keepenvRetains the caller's environment variablesAvoid; use setenv { VAR } to pass only what is needed
as targetRestricts the target user (default: all users)Always set, usually as root or a service user
cmd and argsRestricts command and arguments (default: all commands)Use absolute paths, as the manual advises; args alone means no arguments

Example scoped rules (replace the shipped permit keepenv :wheel):

  • permit persist :wheel as root for a small admin group that must type its password.
  • permit nopass backup as root cmd /usr/sbin/dump for a backup service account.
  • deny :staff placed after broader rules if a sub-group must be excluded (remember the last match wins).

securelevel limits even root. At level 1 (the multi-user default) /dev/mem and /dev/kmem cannot be opened, raw disks of mounted filesystems are read-only and system immutable and append-only file flags cannot be removed. Level 2 adds read-only raw disks whether mounted or not and stops the clock being set backwards; the manual notes it can also limit the damage of a compromised firewall by prohibiting changes to packet filter rules. Only init can lower securelevel, so a change requires a reboot, which is the point. Combine level 2 with schg flags on critical binaries and configuration for appliances such as firewalls. For cross-platform guidance on superuser accounts see the Root, sudo and superuser accounts on Linux and Unix guide; ATT&CK tracks abuse of elevation tools as T1548.003 Sudo and Sudo Caching.

pledge, unveil and the exploit mitigations

OpenBSD's security page describes a file-by-file audit of critical components that has run since the summer of 1996, fixing bugs whether or not exploitability is proven, and a stream of mitigations that make the bugs that remain harder to exploit.

pledge(2)

pledge separates the POSIX feature set into about three dozen subsystems. A program declares the promises it needs, for example stdio rpath inet dns; subsystems not listed become unavailable, and most attempts to use them kill the process with an uncatchable SIGABRT. Later calls can only reduce promises, and execpromises sets what an executed child may use. Even with promises, some behaviour tightens on the first call: PROT_EXEC mappings need the prot_exec promise, setuid and setgid bits are ignored on chmod, and only a few ioctl operations are allowed. pledge first appeared in OpenBSD 5.9.

unveil(2)

The first call to unveil removes visibility of the entire filesystem except the named path with permissions r, w, x and c (create and remove). Further calls add paths; calling unveil(NULL, NULL) or a pledge without the unveil promise locks the list, which the manual strongly recommends. Disallowed access returns EACCES or ENOENT, and lastcomm(1) marks a terminated process with the U flag if unveil blocked file access. unveil first appeared in 6.4. The manual warns that programs misbehave when files disappear, so unveil directories rather than individual files.

MitigationWhat it doesAttack it raises the cost of
pledgeSystem call restriction by promise groupPost-exploitation shell, network or file access from a compromised daemon
unveilPer-process filesystem viewReading keys, configuration or other users' data after compromise
Privilege separationSmall privileged parent, unprivileged chrooted workerRoot compromise through a parsing bug
W^X (since 3.3), execute-only code where supportedMemory is writable or executable, not bothCode injection
Randomised malloc and mmap, PIE, library order randomisation, random kernel relinkingUnpredictable memory layoutMemory corruption exploits relying on known addresses
Stack protector, RETGUARDPer-function cookies checking return addressesReturn-oriented programming
Immutable memory and pinsyscallsLocks mappings and pins where system calls can be made fromChanging memory permissions and calling the kernel from injected code

What this means for you: base daemons already pledge and unveil, but third-party packages may not. When you write or commission software for OpenBSD, call pledge and unveil early in main() after configuration is read, and test with the narrowest promises that work. Mitigations map to NIST SP 800-53 SI-16 Memory Protection and SC-39 Process Isolation.

Integrations, API tokens and service accounts

  • SSH keys are the main machine credential. Automation, backup and configuration management reach OpenBSD hosts over SSH. Use one key per job, restrict with from= and forced commands in authorized_keys, and pair with a single-command doas rule. Hardening detail is in the OpenSSH Server Hardening Guide (OpenSSH is developed by the OpenBSD project).
  • Daemon credentials: keys and secrets for relayd, httpd, iked, smtpd and similar daemons belong in root-owned files readable only by the daemon's privileged parent; unveil reduces what a compromised worker can read.
  • Configuration management: agents and pull-based tools typically need root; prefer push over SSH with scoped doas rules to a long-running root agent, and keep their tokens out of world-readable files.
  • Patch infrastructure: syspatch fetches from the mirror named in /etc/installurl and verifies patches before installing (its manual refers to signify(1)). Point every host at a mirror you trust and monitor outbound access to it.
  • pf user rules: pf can match traffic by local user, as the default ruleset does to keep the _pbuild user off the network. Use the same technique to restrict which service users may make outbound connections.

Firewalling with pf

The shipped /etc/pf.conf contains set skip on lo, block return, pass (establish keep-state), a block on inbound X11 ports 6000 to 6010 on non-loopback interfaces and a block on outbound traffic for the _pbuild user. In other words, it is permissive. The pf FAQ recommends a default-deny policy whose first filter rule is block all. pf uses last-matching-rule-wins unless a rule has quick, keeps state for TCP, UDP and ICMP by default, logs matching packets through pflogd(8) when a rule has log, and supports urpf-failed for reverse path checks.

ElementBaseline choiceWhy
Default policyblock log all firstAnything not explicitly allowed is dropped and visible
Spoofingantispoof for each interface and block in quick from urpf-failedDrops packets claiming addresses from the wrong side
Management accessSSH only from a management table, for example <admins>Limits brute force (T1110) and SSH lateral movement (T1021.004)
ServicesExplicit pass in per published portMatches the service inventory
EgressPass out by interface, user and destination where practicalLimits command-and-control and data exfiltration
Brute-force tablesmax-src-conn-rate with overload <bruteforce> flushAutomatically blocks abusive sources

Check syntax with pfctl -nf /etc/pf.conf before loading, keep the previous ruleset to roll back with pfctl -f, and if you run securelevel 2, plan rule changes around reboots. General ruleset review practice is in the Firewall Rule Review Checklist.

Logging and detection

SourceWhat it tells youWatch for
security(8) daily mailAccount file problems, setuid and setgid changes, changes to files in /etc/mtree/special and your own .secure lists, /etc/changelist diffs, disklabel changes, package installs and removalsAny unexpected change; build mtree lists for critical directories
Authentication logsSSH logins and doas use (doas logs successful execution to syslogd unless nolog)New source addresses, root logins, doas by unexpected users
pflogPackets matching log rulesBlocked inbound scans, unexpected outbound connections
lastcomm(1) accountingProcesses flagged after pledge or unveil violationsAny flagged daemon: a possible exploitation attempt
syspatch -cPatches available but not installed (suitable for cron)Non-empty output older than your patch SLA

Forward syslog to a central collector so that evidence survives a compromised host. A daemon killed by pledge is a signal worth an alert: it may be a bug, or it may be an exploit hitting the wall the mitigation built, as covered for exploitation in T1068 Exploitation for Privilege Escalation.

Metrics: percentage of hosts on a supported release; days from errata publication to syspatch install; number of doas rules with nopass or without cmd; percentage of hosts with a default-deny pf policy; number of unreviewed changes in the daily security report; percentage of hosts at securelevel 2 among appliances.

Hardening baseline

  1. Install minimal: select only the sets you need, enable only required daemons, and review what runs with rcctl ls on.
  2. Accounts and SSH: named admin accounts, key or certificate login, PermitRootLogin no, and password authentication off where keys are in place.
  3. doas: replace the sample rule with scoped rules; no nolog, no blanket nopass.
  4. pf: default-deny with antispoof, management tables and logging; test with pfctl -nf and keep the previous file for rollback.
  5. Patching: run syspatch on amd64, i386 and arm64 (it keeps a rollback tarball; syspatch -r reverts the last patch), update packages, and plan a release upgrade every six months so you never fall outside the two supported releases.
  6. Integrity: create /etc/mtree/*.secure lists for critical directories, set immutable flags on appliance configuration and raise securelevel to 2 where operations allow.
  7. Logging: forward syslog and pflog centrally, forward root's mail, enable process accounting if you want pledge and unveil violation evidence.
  8. Review: quarterly review of doas rules, SSH keys, pf rules and the service list.
Control areaNIST CSF 2.0NIST SP 800-53 Rev. 5
Minimal services, secure configurationPR.PS-01CM-6, CM-7
doas least privilege, securelevelPR.AA-05AC-6
pf default deny and segmentationPR.IR-01SC-7
syspatch and supported releasesPR.PS-02SI-2
pledge, unveil, memory mitigationsPR.PS-01SI-16, SC-39
mtree, changelist and the security reportDE.CM-09SI-7, AU-2

Common misconfigurations

  • Trusting the default pf.conf: it passes traffic; a "firewall" built on it may block nothing but X11.
  • Running an unsupported release: no more errata. Stay on a supported release, apply security updates promptly with syspatch and watch the OpenBSD errata page.
  • Keeping permit keepenv :wheel and adding nopass: every wheel member, and anyone who steals their session, gets passwordless root.
  • Using nolog in doas rules: privileged actions disappear from the audit trail.
  • Ignoring the daily security mail: root's mail goes nowhere, so setuid and changelist alerts are never read.
  • Assuming packages are pledged: third-party software may run with full system call access; contain it with dedicated users, chroot and pf user rules.

Practitioner checklist

  • Every host runs OpenBSD 8.0 or 7.9 (the supported releases at 8 November 2026) and has a release upgrade date planned.
  • syspatch -c runs from cron and missing errata are installed within your patch SLA.
  • Only required daemons are enabled; the list is reviewed with rcctl ls on.
  • doas.conf uses scoped rules with target users and absolute command paths; no nolog; nopass only for single commands.
  • SSH uses named accounts and keys, with root login disabled.
  • pf starts with block log all, uses antispoof and management tables, and changes are syntax-checked before load.
  • Appliances run at securelevel 2 with immutable flags on critical files.
  • Root's mail is forwarded and the daily security report is reviewed.
  • Syslog and pflog are forwarded to a central collector.
  • In-house software for OpenBSD calls pledge and unveil and locks unveil after setup.

Standards and references

Related NHI Mgmt Group resources: FreeBSD Security Hardening Guide · OpenSSH Server Hardening Guide · Root, sudo and superuser accounts on Linux and Unix · Patch Management Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 8 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org