OpenBSD is a free, 4.4BSD based operating system whose source history begins in October 1995 as a fork of NetBSD. It ships a release roughly every six months, and each release gets errata patches on its -stable branch for one year, so two releases are supported at any time. OpenBSD 8.0, released on 20 October 2026, is the project's 61st release. Along the way OpenBSD was the first to turn on several exploit mitigations by default (systemwide ProPolice and W^X in 3.3, address randomization in 3.4, PIE in 5.3), and it added two system calls, pledge(2) in 5.9 and unveil(2) in 6.4, that let a program give up the system calls and files it does not need.
This post walks through that history release by release, explains how pledge and unveil actually restrict a process, lists the projects that grew out of OpenBSD (OpenSSH, LibreSSL, PF, OpenBGPD, OpenNTPD, doas and more), and shows how errata, syspatch(8) and sysupgrade(8) keep a running system patched. Every date below comes from OpenBSD's own release pages, innovations page, errata pages and manual pages, linked in the Sources section.
Key takeaways
- Cadence: a release about every six months (targets: May and November); each release's -stable branch gets errata for one year, so two releases are supported.
- Current state (23 October 2026): OpenBSD 8.0 shipped on 20 October 2026 and already has five errata. OpenBSD 7.9 (19 May 2026) is still supported. OpenBSD 7.8 (22 October 2025) reaches the end of its one year -stable window this week; its errata page still received three security fixes on 20 October 2026.
- Firsts by default: systemwide ProPolice and W^X on several architectures in 3.3 (May 2003), ASLR in 3.4 (November 2003), PIE globally in 5.3 (May 2013).
- pledge and unveil: pledge(2) (5.9, March 2016) limits a process to about three dozen named subsystems and kills it with SIGABRT if it strays. unveil(2) (6.4, October 2018) hides every path a program did not name.
- Randomization and recent work: libc, libcrypto, ld.so, sshd and, since OpenBSD 6.2, the kernel itself (KARL) are relinked in random order at boot. Since 2022 OpenBSD added immutable memory, execute only code, IBT and BTI branch enforcement (7.4) and pinsyscalls(2) (7.5).
- Patching: syspatch(8) (6.1) installs signed binary errata on amd64, i386 and arm64 and can roll them back; sysupgrade(8) (6.6) moves to the next release; packages need pkg_add -u.
- Spin offs: OpenSSH (2.6, 1999), PF (3.0, 2001), OpenBGPD, OpenNTPD, OpenSMTPD, LibreSSL (5.6, 2014), doas (5.8) and rpki-client all started in the OpenBSD tree.
- Funding: volunteers develop OpenBSD; the OpenBSD Foundation, a Canadian not for profit, funds infrastructure and hackathons.
How OpenBSD started and how its release cycle works
Why did OpenBSD fork from NetBSD in 1995?
OpenBSD is a fork of NetBSD. The project's public source history, mirrored on GitHub, contains commits by Theo de Raadt dated 18 and 19 October 1995, which is where the OpenBSD tree starts. Theo de Raadt had been a NetBSD developer before that; OpenBSD's own innovations page credits him with starting the NIS client tools (ypbind, ypcat and friends) that were imported into NetBSD on 26 April 1993 and first shipped with NetBSD 0.9.
The personal circumstances of the split are told in old mailing list archives and differ depending on who tells them. This post sticks to what the project itself documents. The project goals page states the direction that followed: full source access, integrating good code under acceptable licenses (ISC or Berkeley style preferred, the GPL not acceptable for new code), fixing security problems "before anyone else does", integrated cryptography exported legally from Canada, and a release approximately every six months.
Two of those goals shaped everything that follows. Proactive security meant fixing bugs as classes, not one report at a time. The license preference meant that anything OpenBSD built could be lifted into other operating systems and commercial products without legal friction. That second point is why so much OpenBSD code now runs on machines that have never booted OpenBSD. If you want the background on that license family, our explainer on the BSD 3 clause license covers it.
The home page also carries the project's long running tagline about the default install: "Only two remote holes in the default install, in a heck of a long time!" It is a claim about the default install only, not about software you add or services you enable, a distinction that matters again when we look at what syspatch covers.
How does the six month release and two release support cycle work?
OpenBSD's FAQ states that the team makes a new release approximately every six months, with target release dates in May and November. In practice the dates drift a little: OpenBSD 7.7 shipped on 28 April 2025, 7.8 on 22 October 2025, 7.9 on 19 May 2026 and 8.0 on 20 October 2026.
Version numbers move by 0.1 per release and are not semantic: 7.9 to 8.0 is just the next release. Counting from OpenBSD 2.0, the home page confirms 8.0 is the 61st release.
The project describes three "flavors" of the system:
| Flavor | What it is | Who should run it |
|---|---|---|
| -release | The release as shipped on the install media | Starting point for a new install |
| -stable | The release plus errata patches; no new features, hardware support or API changes | Production systems that want fixes only |
| -current | The development branch, distributed as snapshots | Developers, testers and people who need new hardware support |
The FAQ says new users should run either -stable or a release. The errata pages state that patches for supported releases are incorporated into the -stable branch, "which is maintained for one year after release". With two releases a year, that means the current release and the one before it are supported at any given time, and each release has a window of roughly twelve months. There is no long term support release. If you run OpenBSD, you upgrade at least once a year, ideally every six months.
Here is what that looked like on 23 October 2026:
| Release | Released | Status on 23 October 2026 | Errata so far |
|---|---|---|---|
| OpenBSD 8.0 | 20 October 2026 | Current release, supported | 5 (4 security, 1 reliability) |
| OpenBSD 7.9 | 19 May 2026 | Previous release, supported | 40 (26 security, 14 reliability) |
| OpenBSD 7.8 | 22 October 2025 | One year window ends this week | 75 (45 security, 30 reliability) |
The counts come from each release's errata page. A release is not "done" when it ships: OpenBSD 8.0 had four errata on its release day and a fifth three days later.
Every release that changed OpenBSD's security model
OpenBSD has shipped 61 releases, and most of them carry some security change. The table below is the short list: the releases where a mitigation, an API or a tool arrived that changed how the system defends itself. Dates are the release dates printed on each release's page on openbsd.org, and the feature attributions come from the release pages and the innovations page.
| Release | Released | Headline security change |
|---|---|---|
| 2.0 | 1996 | First OpenBSD release; issetugid(2) (August 1996) |
| 2.1 | About 1 June 1997 | arc4random(3) and bcrypt(3) first released; IPsec stack imported February 1997 |
| 2.6 | 1 December 1999 | OpenSSH first released, forked from SSH 1.2.12 |
| 3.0 | 1 December 2001 | PF packet filter replaces IPFilter |
| 3.2 | 1 November 2002 | Privilege separation (first in OpenSSH, March 2002); systrace |
| 3.3 | 1 May 2003 | ProPolice stack protector systemwide; W^X on sparc, sparc64, alpha, hppa; read only GOT and PLT |
| 3.4 | 1 November 2003 | ASLR by default; shared libraries loaded in random order; ProPolice in the kernel |
| 4.4 | 1 November 2008 | malloc(3) reimplemented by Otto Moerbeek with randomization and guard pages |
| 5.3 | 1 May 2013 | PIE by default on seven platforms; per shared object stack cookies; SMEP and SMAP support |
| 5.5 | 1 May 2014 | signify(1) signed releases; explicit_bzero(3); PIE on i386 |
| 5.6 | 1 November 2014 | LibreSSL; httpd(8); reallocarray(3); getentropy(2); stack protector extended to arrays (like stack-protector-strong) |
| 5.8 | 18 October 2015 | doas(1) replaces sudo in base; tame(2) work starts |
| 5.9 | 29 March 2016 | pledge(2) (renamed from tame); 453 of 707 base binaries pledged |
| 6.0 | 1 September 2016 | W^X strictly enforced (wxallowed); SROP mitigation; libc relinked at boot |
| 6.1 | 11 April 2017 | syspatch(8) binary patches; RELRO applied to all programs and libraries |
| 6.2 | 9 October 2017 | KARL kernel relinking at boot; libcrypto and ld.so relinked at boot; syspatch -c at first boot |
| 6.4 | 18 October 2018 | unveil(2); RETGUARD on amd64 and arm64; MAP_STACK checks |
| 6.6 | 17 October 2019 | sysupgrade(8) |
| 7.3 | 10 April 2023 | Immutable memory (mimmutable); execute only code on several architectures; sshd relinked at boot; pinsyscall for execve |
| 7.4 | 16 October 2023 | Indirect branch enforcement: IBT on amd64, BTI on arm64, kernel and userland |
| 7.5 | 5 April 2024 | pinsyscalls(2) pins every system call entry point |
| 7.8 | 22 October 2025 | More socket options moved from "inet" to "stdio" in pledge; kernel stack guard page on 64 bit platforms |
| 7.9 | 19 May 2026 | "tmppath" promise retired; __pledge_open(2) for libc internal files |
| 8.0 | 20 October 2026 | syspatch hardened against malicious scripts; man(1) and makewhatis(8) unveiled; pax(1) extraction fixes |
The rest of this section explains the eras behind that table.
1996 to 2002: safer APIs, privilege separation and the first spin offs
The early years were about code more than mitigations. The innovations page lists C library functions from this period that replaced bug prone patterns: issetugid(2) (August 1996), arc4random(3) and bcrypt(3) (first released with OpenBSD 2.1), and strlcpy(3) and strlcat(3) (July 1998, OpenBSD 2.4), which always terminate the destination string and make truncation easy to detect. OpenBSD was also the first free operating system to provide an IPsec stack, imported on 20 February 1997.
Two projects from this era became infrastructure for everyone. OpenSSH started as a fork of SSH 1.2.12 by Tatu Ylonen, was imported on 26 September 1999 and first shipped with OpenBSD 2.6. PF was written by Daniel Hartmeier and Henning Brauer as a replacement for the non free IPFilter (ipf) by Darren Reed, imported on 24 June 2001 and first shipped with OpenBSD 3.0.
Privilege separation, first implemented by Niels Provos and Markus Friedl in OpenSSH in March 2002 and released with OpenBSD 3.2, splits a daemon into a small privileged process and a larger unprivileged one that handles untrusted input. If the network facing part is compromised, the attacker lands in a process with no special rights. The innovations page now lists dozens of base programs built this way, from bgpd, ntpd, httpd and smtpd to tcpdump, tmux, file(1) and pkg_add. OpenBSD 3.2 also shipped systrace, a policy based system call filter that was deleted after OpenBSD 5.9 because the innovations page judges pledge a better mechanism. OpenBSD removes old mechanisms when a newer one makes them redundant.
2003: W^X, ProPolice and ASLR
OpenBSD 3.3 (1 May 2003) is the release most people mean when they talk about OpenBSD's mitigation work.
- ProPolice stack protector. Developed from 2001 by Hiroaki Etoh, ProPolice puts a random canary between local buffers and the saved return address and reorders locals so buffers cannot overwrite pointers. The innovations page says OpenBSD 3.3 "was the first operating system to enable it systemwide by default". OpenBSD 3.4 extended it to the kernel.
- W^X ("write xor execute"). A page can be writable or executable, never both, which breaks the classic attack of writing code into a buffer and running it. OpenBSD 3.3 enforced it first on sparc, sparc64, alpha and hppa, the platforms with a pure execute bit in the MMU. The 3.3 release page notes that i386 and powerpc did not support W^X in 3.3, though the development branch already did on i386.
- GOT and PLT protection. The global offset table and procedure linkage table became read only outside ld.so itself, extended to constructor and destructor sections in 3.4.
OpenBSD 3.4 (1 November 2003) added ASLR. The innovations page describes 3.4 as the first widely used operating system to ship ASLR by default, and the release page describes ld.so loading libraries in random order into randomized addresses, working together with W^X and ProPolice. OpenBSD 3.6 (1 November 2004) made sure every exec time randomization is reapplied each time a program is executed.
2008 to 2014: hardened malloc, PIE, signify and LibreSSL
Otto Moerbeek reimplemented malloc(3) for OpenBSD 4.4 (1 November 2008), building on earlier randomization, guard page and delayed free work. Allocations land at random addresses and freed chunks are not reused immediately, so heap bugs are more likely to crash than to be exploited. A crash is a bug report; silent corruption may be someone else's shell. Our post on what AddressSanitizer catches and what it costs compares that development time approach with production allocators.
OpenBSD 5.3 (1 May 2013) built position independent executables by default on seven platforms, which the innovations page says made it the first widely used operating system to enable PIE globally by default. PIE matters because ASLR can only move code compiled to be movable. The same release gave each shared library its own stack protector cookie and added support for the SMEP and SMAP processor features. Our guide to C and C++ compiler hardening flags covers the stack protector, PIE and RELRO flags that descend from this work on other platforms.
OpenBSD 5.5 (1 May 2014) introduced signify(1) to sign releases and packages. LibreSSL followed: started on 13 April 2014 as a fork of OpenSSL 1.0.1g and first released with OpenBSD 5.6 (1 November 2014). The 5.6 release notes describe the cleanup, such as using standard libc routines instead of custom wrappers and relying on arc4random_buf instead of the old random number generator. 5.6 also added reallocarray(3), getentropy(2) and httpd(8), and extended the stack protector to functions with local arrays, which the release page says matches GCC's stack-protector-strong.
2015 to 2016: doas, pledge and strict W^X
OpenBSD 5.8 (18 October 2015) replaced sudo in base with the much smaller doas(1), and started work on a containment facility called tame(2). OpenBSD 5.9 (29 March 2016) shipped it as pledge(2); the release page says 453 of the 707 base system binaries had already been adapted, and that fixing them exposed ordinary bugs along the way.
OpenBSD 6.0 (1 September 2016) made W^X strict. A program can only violate it if its executable is marked PT_OPENBSD_WXNEEDED and it lives on a filesystem mounted wxallowed. The installer sets /usr/local to wxallowed for third party software such as JIT compilers, so the exception is visible in the mount table and limited to one place. 6.0 also added a sigreturn oriented programming (SROP) mitigation and began relinking libc.so in random order at every boot.
2017 to 2019: syspatch, KARL, unveil, RETGUARD and sysupgrade
OpenBSD 6.1 (11 April 2017) introduced syspatch(8) for signed binary errata patches, and applied read only after relocation protection to all programs and libraries. OpenBSD 6.2 (9 October 2017) brought Kernel Address Randomized Link (KARL): a "link-kit" relinks the kernel's object files in random order, so each boot runs a unique kernel. 6.2 also extended boot time relinking to libcrypto and ld.so and made fresh installs run syspatch -c at first boot.
OpenBSD 6.4 (18 October 2018) delivered unveil(2) and RETGUARD, a per function random cookie that protects the return address and makes return oriented programming harder; it reached mips64 in 6.7 and powerpc in 6.9. 6.4 also added MAP_STACK checks that catch a stack pointer moved to non stack memory. OpenBSD 6.5 (1 May 2019) let programs unveil broad paths such as the whole filesystem read only, which made unveil practical in many more programs, and OpenBSD 6.6 (17 October 2019) added sysupgrade(8).
2022 to 2024: immutable memory, execute only code and pinned system calls
Recent work targets what attackers do after finding a bug: change memory permissions, read code for gadgets, or call the kernel from unexpected places.
- Immutable memory (December 2022, OpenBSD 7.3). Permissions on most of a program's static address space (main program, ld.so, main stack, load time libraries) are locked, so later mmap, mprotect or munmap calls fail with EPERM.
- Execute only code (from December 2022). On arm64, riscv64, amd64 and several other architectures, program text cannot be read as data. The innovations page notes that a lot of careless userland code had to be fixed first.
- sshd relinked at boot (January 2023). Since OpenBSD 7.3, sshd gets an unknown address layout after every reboot.
- Branch target enforcement (OpenBSD 7.4). IBT on amd64 and BTI on arm64 in both kernel and userland, so indirect jumps can only land on marked instructions.
- Pinned system calls (OpenBSD 7.5). ld.so tells the kernel the exact entry location of every system call in libc.so, and the kernel refuses calls from anywhere else. OpenBSD 7.6 then deleted the older msyscall mechanism as redundant.
2025 to 2026: tightening the edges
OpenBSD 7.8 moved low risk socket options into the basic "stdio" promise, so programs need the broader "inet" promise less often, and added a kernel stack guard page on 64 bit platforms. OpenBSD 7.9 retired the "tmppath" promise in favour of unveiling /tmp, and added __pledge_open(2) so libc can open a few tightly controlled files (time zone data, resolver configuration) read only even under strict pledge and unveil. OpenBSD 8.0 hardened syspatch against malicious scripts, unveiled man(1) and makewhatis(8), and stopped pax(1) extracting archives outside the working directory.
What are pledge and unveil, and how do they restrict a program?
pledge and unveil are the two OpenBSD features most worth understanding if you write software, because they are mitigations the programmer controls, not the operating system alone.
How pledge works
The pledge(2) manual page describes the system call this way: it "separates the POSIX feature set into a group of approximately 3 dozen subsystems". A program calls pledge with a space separated string of promises naming the subsystems it will need from now on. Everything not listed becomes unavailable. If the program then tries an operation from a subsystem it gave up, the kernel usually kills it with an uncatchable SIGABRT and writes a core file if it can.
Two properties make pledge useful in practice:
- It only ratchets down. Later calls to pledge can remove more promises but can never add back one that was dropped. A compromised program cannot undo its own restrictions.
- It is called by the program, at the right moment. A program typically starts with broad needs (read configuration, open sockets, load certificates), does that setup, and then pledges down to what its main loop needs. The restriction applies exactly when the program starts handling untrusted input.
Some promises you will see in nearly every pledged program:
| Promise | What it allows (summarised from pledge(2)) |
|---|---|
| stdio | Basic memory management, operations on already open file descriptors, timers, and other basics most programs need |
| rpath | Path traversal, stat, and opening files for reading |
| wpath | Like rpath, but opening files for writing |
| cpath | Creating and removing files and directories |
| inet | Sockets in the AF_INET and AF_INET6 domains, with reduced setsockopt |
| dns | The low level behaviours the DNS resolver needs, such as reading resolv.conf |
| proc | fork, vfork, kill and related process operations |
| exec | Calling execve; with execpromises, the new program starts under those promises |
| unveil | Permission to keep calling unveil(2) |
| error | Return ENOSYS on violation instead of killing the process |
The first call to pledge also changes some POSIX behaviour regardless of promises: per the manual page, setuid and setgid bits are ignored on chmod, ioctl is limited to a handful of operations, and mmap and mprotect refuse PROT_EXEC unless the prot_exec promise is present.
A second argument, execpromises, sets the promises a program will have after execve, so a parent can start its children already restricted.
How unveil works
unveil(2) restricts the filesystem view instead of the system call set. According to its manual page, the first call to unveil "removes visibility of the entire filesystem" from all other filesystem related system calls, except for the path and permissions just named. Further calls add more paths. Permissions are a string of characters:
| Permission | Meaning | Corresponding pledge promises |
|---|---|---|
| r | Path available for reading | rpath |
| w | Path available for writing; connect to Unix sockets in the filesystem | wpath, chown, fattr |
| x | Path available for execution | exec |
| c | Path can be created and removed | cpath, dpath, unix |
A directory unveils everything underneath it, unless a more specific unveil exists lower down. Accessing a path that is unveiled with the wrong permission returns EACCES. Accessing a path that is not unveiled at all returns ENOENT, so to the program it simply does not exist. After setup, a program should lock unveil by calling it with two NULL arguments, or by calling pledge without the "unveil" promise.
The manual page is candid about the limits. unveil does not survive execve, and the page warns that stripping arbitrary paths from arbitrary programs is dangerous. It is a tool for a developer protecting their own program, not a sandbox wrapped around someone else's binary.
pledge and unveil together
The two calls are designed to be used together. pledge removes whole categories of system calls; unveil narrows the paths the remaining file system calls can touch. A typical pattern looks like this in C:
#include <err.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
/* Setup phase: only these paths will exist for this process. */
if (unveil("/etc/myapp.conf", "r") == -1)
err(1, "unveil config");
if (unveil("/var/myapp", "rwc") == -1)
err(1, "unveil data dir");
/* Lock unveil so no new paths can be added later. */
if (unveil(NULL, NULL) == -1)
err(1, "unveil lock");
/* Main loop needs files and networking, nothing else. */
if (pledge("stdio rpath wpath cpath inet dns", NULL) == -1)
err(1, "pledge");
/* ... read config, open sockets, serve requests ... */
/* After sockets are open, drop dns and path access entirely. */
if (pledge("stdio inet", NULL) == -1)
err(1, "pledge");
return 0;
}
It is a few lines in main, placed after setup and before untrusted input. That is the design lesson, whatever platform you build for: a program knows better than any outside policy what it needs, so let it declare that, and enforce the declaration in the kernel.
How pledge compares with sandboxing on other systems
Other operating systems offer related mechanisms with different trade offs. This table compares approaches using each project's own documentation; it does not claim that one was copied from another.
| Mechanism | System | Who writes the policy | Granularity | Source |
|---|---|---|---|---|
| pledge(2) | OpenBSD 5.9 and later | The program itself, as a promise string | About three dozen subsystems | pledge(2) manual |
| unveil(2) | OpenBSD 6.4 and later | The program itself | Paths with r, w, x, c permissions | unveil(2) manual |
| seccomp filters | Linux | The program, as a BPF filter over system call numbers and arguments | Individual system calls | Linux kernel seccomp filter documentation |
| Landlock | Linux | The program, as a ruleset; unprivileged | Filesystem access rights, and in later ABI versions network ports | Linux kernel Landlock documentation |
| Capsicum | FreeBSD 9.0 and later | The program enters capability mode and holds rights on descriptors | Capabilities on file descriptors | FreeBSD capsicum(4) manual |
The practical difference is ergonomics. A seccomp filter must name system calls, which differ between architectures and libc versions; pledge names intentions ("stdio inet") and lets the kernel and libc keep the mapping right. Landlock is closer to unveil, and Capsicum makes open file descriptors the only way to reach resources.
Which widely used projects came out of OpenBSD?
The OpenBSD home page lists its "associated projects" as OpenSSH, OpenBGPD, rpki-client, OpenNTPD, OpenSMTPD, OpenIKED, mandoc and LibreSSL. Combined with the innovations page, here is where each started:
| Project | Started or imported | First released with | What it does |
|---|---|---|---|
| OpenSSH | Imported 26 September 1999 (fork of SSH 1.2.12) | OpenBSD 2.6 | Remote login, file transfer and tunnelling over SSH |
| PF | Imported 24 June 2001 | OpenBSD 3.0 | Stateful packet filter, NAT and traffic normalisation |
| OpenBGPD | Imported 17 December 2003 | OpenBSD 3.5 | BGP routing daemon |
| OpenNTPD | Imported 31 May 2004 | OpenBSD 3.6 | Time synchronisation daemon |
| OpenSMTPD | Imported 1 November 2008 | OpenBSD 4.6 | Mail transfer agent |
| OpenIKED | Imported 3 June 2010 | OpenBSD 4.8 | IKEv2 VPN daemon |
| signify | Imported 31 December 2013 | OpenBSD 5.5 | Signing and verifying releases and packages |
| LibreSSL | Started 13 April 2014 (fork of OpenSSL 1.0.1g) | OpenBSD 5.6 | TLS and crypto library |
| doas | Imported 16 July 2015 | OpenBSD 5.8 | Run commands as another user |
| syspatch | Imported 5 September 2016 | OpenBSD 6.1 | Binary errata patches |
| sysupgrade | Imported 25 April 2019 | OpenBSD 6.6 | Release upgrades |
| rpki-client | Imported 17 June 2019 | OpenBSD 6.7 | Route origin validation for BGP |
OpenSSH is the clearest case of OpenBSD code becoming general infrastructure. Its project page announces OpenSSH 10.6, released 6 October 2026, and offers separate portable releases for other systems; LibreSSL, OpenBGPD, OpenNTPD and OpenSMTPD follow the same pattern. That matters for supply chain thinking: plenty of servers, appliances and container images carry OpenBSD code without running OpenBSD, and they receive its security fixes on their own distribution's schedule, not OpenBSD's.
How are errata and syspatch used to patch a running system?
What an erratum is
Each release's errata page lists numbered patches marked SECURITY FIX or RELIABILITY FIX, with date, affected architectures, a description and a source patch signed with signify(1). syspatch(8) applies binary versions on amd64, i386 and arm64; other architectures get only machine independent binary updates, which the page describes as very rare, so they patch from source.
Per the -stable page, errata are made for bugs that affect many people, and new functionality, hardware support or APIs are never merged.
On release day, 20 October 2026, OpenBSD 8.0 already had a ppp(4) reliability fix and three security fixes: backported nsd(8) fixes, a remotely triggerable kernel heap overflow in IPsec with AES-GMAC on amd64 with AES-NI and on octeon, and use after free bugs in video(4). On 23 October 2026 a fifth erratum added a new dbupdate utility to refresh /etc/ssl/cert.pem and the time zone database, and shipped an updated certificate bundle. That last one is a good reminder that "patching" covers trust stores and data files, not only code.
What syspatch does
The syspatch(8) manual page describes it as "a utility to fetch, verify, install and revert OpenBSD binary patches". Run with no options, it:
- applies all missing patches;
- creates a rollback tarball containing the files it is about to replace;
- extracts and installs the files from each syspatch tarball.
Patches are cumulative, so you cannot install only a subset. If you did not install a set (for example the X window system sets), patches for it are skipped. The options are short: -c lists available patches and is suitable for cron, -l lists installed patches, -r reverts the most recent patch and -R reverts all of them.
syspatch is for release installs, not custom kernels or -current snapshots. Kernel patches need a reboot, because the running kernel stays in memory until you restart. OpenBSD 8.0 hardened syspatch itself against malicious scripts and stopped it downloading whole tarballs when only checking for updates.
What syspatch does not do
syspatch covers the base system only. Third party software installed from packages (anything under /usr/local) is updated with pkg_add -u. Firmware for some devices is handled by fw_update(8). Moving to the next release is sysupgrade(8). If you only run syspatch, your web application stack, language runtimes and databases from packages may be months out of date.
Step by step: install, patch, update packages and read pledge promises
The commands below are for a test machine or a server you control. They use OpenBSD 8.0 on amd64 as the example; swap the version numbers for the release you run.
Step 1: download and verify the install image
On another OpenBSD machine, download miniroot80.img, SHA256 and SHA256.sig from a mirror, then verify the signature with the release's signify key, as shown in the OpenBSD FAQ:
# Check the image is intact and signed by the OpenBSD 8.0 base key
signify -Cp /etc/signify/openbsd-80-base.pub -x SHA256.sig miniroot80.img
# Expected:
# Signature Verified
# miniroot80.img: OK
A checksum alone only detects accidental corruption. On other operating systems, the FAQ warns, the signify package may not include OpenBSD's public key, so get it from a source you trust.
Step 2: write the image to a USB drive
Warning: the next command overwrites the target device completely. Writing to the wrong device destroys whatever is on it, including your own system disk. Check the device name first, every time.
# On OpenBSD: list disks and confirm which one is the USB stick
sysctl hw.disknames
dmesg | grep -i 'sd[0-9]'
disklabel sd6 | head -20 # confirm size and label match the USB stick
Only when you are certain the device is the USB stick, write the image:
# Replace sd6 with the device you just confirmed
dd if=miniroot80.img of=/dev/rsd6c bs=1M
On other operating systems, use the platform's own disk listing (for example lsblk on Linux or diskutil list on macOS) and confirm the size and model before running dd.
Step 3: install
Boot from the USB stick and choose (I)nstall. The FAQ describes the installer as designed to install OpenBSD with a minimum of user intervention: it asks a short series of questions (keyboard, hostname, network, root password, a few service and user choices, disk layout and which sets to install). A few choices matter for security:
- Do not enable services you will not use. The project's track record is about the default install.
- Create a regular user and use doas(1) for administrative commands.
- Use the automatic disk layout unless you know why not. The FAQ encourages splitting the disk into several filesystems, partly so that a user or a misbehaving program cannot fill every filesystem at once. It also keeps /usr/local, where the installer allows W^X exceptions via wxallowed, separate from the base system.
- When the media lacks SHA256.sig, the installer warns. The FAQ explains that install images do not contain SHA256.sig, so the installer asks whether to continue without verification. If you verified the image in step 1, answering yes is safe.
Warning: the disk setup step erases the disk you select. Before you accept the default layout, confirm the disk name the installer shows (for example sd0) matches the size of the disk you intend to wipe.
Step 4: apply errata with syspatch
After the first boot, log in as root (or use doas) and check for and apply binary patches:
# List patches that are available but not yet installed
syspatch -c
# Install all missing patches (creates a rollback tarball first)
syspatch
# Show what is installed now
syspatch -l
# If a kernel patch was applied, reboot so the new kernel runs
reboot
If a patch causes a problem, revert it:
# Revert the most recently installed patch
syspatch -r
To hear about new errata, put syspatch -c in root's crontab and have the output mailed to you. Installing kernel patches automatically without a planned reboot leaves you thinking you are patched when you are not.
Step 5: update firmware and packages
# Fetch and install firmware needed by this machine's devices
fw_update
# Update every installed package to the latest version for this release
pkg_add -u
# See what is installed and check one package
pkg_info -q | head
pkg_info -I openssh-portable 2>/dev/null || echo "using base OpenSSH"
pkg_add uses the mirror configured in /etc/installurl (installurl(5)) or the PKG_PATH environment variable. The packages FAQ notes that pkg_add -u attempts to update all installed packages, including their dependencies. Package updates are separate from base system errata, so a clean syspatch -c tells you nothing about packages.
Step 6: upgrade to the next release with sysupgrade
When a new release ships (or before your current one leaves its one year window), upgrade:
# Fetch and verify the next release's sets, prepare /bsd.upgrade, but do not reboot yet
sysupgrade -n
# When ready, reboot; the bootloader runs a one shot upgrade
reboot
# After the upgrade boots, apply that release's errata and package updates
syspatch
pkg_add -u
Per its manual page, sysupgrade downloads to /home/_sysupgrade, verifies with signify, copies bsd.rd to /bsd.upgrade and reboots by default. Only one version to the next is tested, and it refuses to start if /usr lacks space. Read the release's upgrade guide first, because some releases need manual steps.
Step 7: see which programs are pledged and read their promises
The pledge(2) manual page says a process running under pledge shows the state flag "p" in ps(1) output. The current ps(1) manual page also documents a pledge keyword that prints the comma separated list of a process's active promises, so on recent releases you can read promises straight from the process table:
# Show processes whose state includes 'p' (running under pledge)
ps -axo pid,stat,user,comm | awk 'NR==1 || $2 ~ /p/'
# On recent releases: print each process's active pledge promises
ps -axo pid,user,comm,pledge
If your release's ps does not know the pledge keyword (check man ps), read the program's source. The base system source is in CVS and mirrored publicly, and a source tree in /usr/src makes it a grep away:
# Find every pledge and unveil call in a base program, for example ping
grep -n 'pledge(\|unveil(' /usr/src/sbin/ping/ping.c
To find programs that were killed for violating pledge or blocked by unveil after the fact, turn on process accounting and read it with lastcomm(1). The rc.conf(8) manual page documents an accounting variable; setting it makes rc run accton(8) on /var/account/acct at boot:
# Enable process accounting from the next boot
echo 'accounting=YES' >> /etc/rc.conf.local
# Later: list commands with mitigation flags in the flags column
lastcomm | awk '$2 ~ /[PUMSB]/'
The lastcomm(1) manual page defines the flags. P means the command was terminated for a pledge violation. U means it tried a file access that unveil prevented. M means it made a system call from writable memory or with the stack pointer outside stack memory. S means it tried a system call from the wrong system call instruction, which is what pinsyscalls catches. B means an indirect branch landed somewhere without a branch target instruction. Any of these is worth a look: either the program does something its developer did not expect, or something made it try. The core file a pledge violation leaves behind is a good place to start.
How is OpenBSD funded and governed?
OpenBSD's own pages are direct about this. The home page says OpenBSD is developed entirely by volunteers and that the development environment and developer events are funded through contributions collected by the OpenBSD Foundation. The FAQ adds that maintainers support the project largely from their own pockets, including the many hardware ports and network resources used to distribute the system.
The OpenBSD Foundation describes itself as a Canadian not for profit corporation whose objects are to support and further the development, advancement and maintenance of free software based on OpenBSD, including the operating system and related projects such as OpenSSH, OpenBGPD, OpenNTPD, OpenSMTPD, LibreSSL, mandoc and rpki-client. It says it uses all funds it receives for infrastructure costs and for developer events and initiatives, typically hackathons. At the time of writing its site is running a 2026 fundraising campaign.
Governance is simple. Theo de Raadt, whose commits open the tree's history in October 1995, leads the project, and the innovations page credits him with many of the mitigations above. The goals page asks that decisions be made on technical merit and as free of politics as possible. The foundation funds; the developers decide and build. For an organisation that depends on OpenSSH or LibreSSL, the most direct way to support that code is a donation to the foundation.
Mitigations and where comparable defences exist elsewhere
This table is not about credit. Ideas in this field often develop in parallel, and several OpenBSD defaults started elsewhere (ProPolice was Hiroaki Etoh's work; RELRO came from the GNU project). The useful question is whether a defence is on by default on the systems you ship to.
| Defence | OpenBSD default since | What it stops | Comparable defence elsewhere |
|---|---|---|---|
| Stack protector | 3.3 (May 2003), systemwide | Overwriting the return address through a stack buffer | GCC's stack-protector family of options, including stack-protector-strong, documented in GCC's instrumentation options |
| W^X | 3.3 on some architectures; strict since 6.0 | Executing injected data | Non executable stack and heap on modern platforms using the processor's no execute bit |
| ASLR | 3.4 (November 2003) | Reliable guessing of library and stack addresses | Address randomization is standard on modern desktop, server and mobile systems |
| PIE by default | 5.3 (May 2013) | A fixed address main program that ASLR cannot move | Compiler and distribution defaults for PIE, covered in our compiler hardening guide |
| KARL | 6.2 (October 2017) | A fixed kernel layout across machines and boots | Kernel address randomization moves the kernel as a whole on several systems; per boot relinking is unusual |
| RETGUARD | 6.4 (amd64, arm64) | Return oriented programming | Hardware shadow stacks and return address signing on newer processors |
| pledge | 5.9 (March 2016) | Compromised code using system calls the program never needed | seccomp filters on Linux; Capsicum capability mode on FreeBSD since 9.0 |
| unveil | 6.4 (October 2018) | Compromised code reading or writing files outside the program's needs | Landlock on Linux |
| IBT and BTI | 7.4 (October 2023) | Jumping into the middle of functions | The same processor features are used by other kernels and toolchains, often opt in |
| pinsyscalls | 7.5 (April 2024) | Making system calls from injected or unexpected code | No common equivalent |
OpenBSD's lasting contribution is less any single mitigation than the habit of turning each one on by default, for every program, and then fixing the software that breaks.
How this history compares with other operating system release models
OpenBSD's support model is the strictest in a typical mixed fleet. Our Debian release history and Ubuntu release history posts describe distributions with roughly five years of free security support for long term releases and paid extensions beyond that. OpenBSD gives each release about a year, in exchange for small, routine upgrades with sysupgrade.
| Question | OpenBSD | Typical long term support Linux distribution |
|---|---|---|
| Release cadence | About every 6 months | Every 2 years for long term releases |
| Free security support per release | About 1 year (two releases supported) | About 5 years, often extendable |
| How fixes arrive | Errata patches on -stable; syspatch binary updates on amd64, i386, arm64 | Package updates from the distribution's security archive |
Common mistakes
- Treating syspatch as "fully patched". syspatch only updates the base system. Packages under /usr/local need pkg_add -u, and firmware needs fw_update. Most real exposure on a typical server sits in packages.
- Forgetting to reboot after a kernel erratum. syspatch installs the new kernel but the old one keeps running until you restart. Schedule the reboot when you patch.
- Staying on a release past its year. Once a release leaves its one year -stable window, errata stop. OpenBSD 7.8 reaches that point this month. Plan the sysupgrade before the deadline, not after.
- Mounting everything wxallowed to make one program work. The wxallowed exception exists for specific software. Turning it on broadly undoes strict W^X for the whole filesystem.
- Pledging before setup is finished. Calling pledge too early kills the program the first time it opens a configuration file. Do setup, unveil, lock unveil, then pledge.
- Assuming unveil follows execve. A program that execs another starts that program with no unveils. Use execpromises with pledge if you need the child restricted.
- Assuming downstream copies of OpenSSH or LibreSSL are patched when OpenBSD is. Other systems ship their own builds on their own schedule. Track those separately.
FAQ
Why did OpenBSD split from NetBSD?
OpenBSD's source history begins in October 1995 as a fork of the NetBSD tree, led by Theo de Raadt, a former NetBSD developer. Accounts of the personal reasons differ; the project documents its direction instead: open source access, permissive licenses, integrated cryptography and fixing security problems early.
How often does OpenBSD release a new version?
About every six months, with target dates in May and November. Recent releases were 7.7 on 28 April 2025, 7.8 on 22 October 2025, 7.9 on 19 May 2026 and 8.0 on 20 October 2026.
How long is an OpenBSD release supported?
The -stable branch of each release, which carries errata patches, is maintained for one year after release. In practice that means the current and previous releases are supported. There is no long term support release.
What is the latest OpenBSD version?
OpenBSD 8.0, released on 20 October 2026, which the project's home page describes as its 61st release.
What is the difference between pledge and unveil?
pledge restricts which groups of system calls a process can use, such as networking, file reading or process creation. unveil restricts which filesystem paths those calls can reach. A program usually uses both: unveil to name the files it needs, pledge to give up everything else.
Does pledge work on Linux?
No. They are OpenBSD system calls. Linux offers seccomp filters and Landlock for similar goals, and FreeBSD has Capsicum.
Was OpenSSH created by OpenBSD?
Yes. OpenBSD developers forked it from SSH 1.2.12 in 1999 and first released it with OpenBSD 2.6. It is still developed in the OpenBSD tree, with portable releases for other systems.
Who funds OpenBSD?
Volunteers develop it. The OpenBSD Foundation, a Canadian not for profit, collects donations and spends them on infrastructure and developer events.
Why software supply chain hygiene still matters here
OpenBSD patches its own base system through errata and syspatch, and nothing replaces that. But an OpenBSD server rarely runs only the base system: the applications deployed on it pull in language packages, libraries and container images, and code that started in OpenBSD, such as OpenSSH and LibreSSL, ships inside other systems and images on their own schedules.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
To be plain about the fit: Safeguard does not patch the OpenBSD base system, replace syspatch or sysupgrade, or analyse kernels or firmware. It helps with the application dependencies you build and deploy, on OpenBSD or anywhere else, and the container images that carry open source components downstream.
The first demo shows the Safeguard CLI in a real session: it reads a vulnerable dependency finding, asks before each command, edits the manifest to the fixed version, runs the install and tests with your approval, and pushes nothing. The same flow applies to an application you deploy on an OpenBSD host, where pkg_add covers the operating system's packages but your project's own lockfile is still yours to keep current.
Click through it at your own pace, or open it full screen.
The second demo sets up the local runner on your own machine, approves it with a device code, and scans from the terminal. It suits teams that want scanning to stay on hardware they control.
Click through it at your own pace, or open it full screen.
The third demo shows the mobile app sending work to a computer running the CLI and approving each command on the phone with Allow once, Allow for turn or Deny. Like pledge, it grants exactly what is needed at the moment it is needed.
Click through it at your own pace, or open it full screen.
You can get the apps at safeguard.sh/download and read the CLI documentation at docs.safeguard.sh/docs/cli.
Quick check
Which OpenBSD release introduced pledge(2), and what happens when a pledged program breaks its promises?
OpenBSD 5.9, released 29 March 2016. In most cases the kernel kills the process with an uncatchable SIGABRT and writes a core file if it can, unless the program pledged the "error" promise, in which case the call fails with ENOSYS.
Does running syspatch keep packages such as a web server from ports up to date?
No. syspatch applies binary errata for the base system only. Third party packages are updated with pkg_add -u, firmware with fw_update, and moving to a new release is done with sysupgrade.
Sources
- OpenBSD home page (current release, associated projects, funding)
- OpenBSD Innovations
- OpenBSD Project Goals
- OpenBSD FAQ: Introduction to OpenBSD
- OpenBSD FAQ: Installation Guide
- OpenBSD FAQ: Building the System from Source
- OpenBSD FAQ: System Management
- OpenBSD -stable branch
- OpenBSD Errata and Patches index
- OpenBSD 8.0 Errata
- OpenBSD 7.9 Errata
- OpenBSD 7.8 Errata
- OpenBSD 2.1 release
- OpenBSD 2.6 release
- OpenBSD 3.0 release
- OpenBSD 3.2 release
- OpenBSD 3.3 release
- OpenBSD 3.4 release
- OpenBSD 3.6 release
- OpenBSD 4.4 release
- OpenBSD 5.3 release
- OpenBSD 5.5 release
- OpenBSD 5.6 release
- OpenBSD 5.8 release
- OpenBSD 5.9 release
- OpenBSD 6.0 release
- OpenBSD 6.1 release
- OpenBSD 6.2 release
- OpenBSD 6.4 release
- OpenBSD 6.5 release
- OpenBSD 6.6 release
- OpenBSD 7.3 release
- OpenBSD 7.4 release
- OpenBSD 7.5 release
- OpenBSD 7.6 release
- OpenBSD 7.7 release
- OpenBSD 7.8 release
- OpenBSD 7.9 release
- OpenBSD 8.0 release
- pledge(2) manual page
- unveil(2) manual page
- syspatch(8) manual page
- sysupgrade(8) manual page
- doas(1) manual page
- pkg_add(1) manual page
- ps(1) manual page
- lastcomm(1) manual page
- rc.conf(8) manual page
- fw_update(8) manual page
- OpenBSD FAQ: Package Management
- The OpenBSD Foundation
- OpenSSH project page
- OpenBSD source mirror on GitHub (commit history from October 1995)
- Linux kernel documentation: Landlock
- Linux kernel documentation: Seccomp BPF
- FreeBSD capsicum(4) manual page
- GCC instrumentation options (stack protector)
Last reviewed: 23 October 2026. OpenBSD errata and supported releases change every few weeks; check the errata page for your release before relying on the counts above.