As I told you before, I really wish we could stop using prot_exec in the ports tree. In some huge ports it's unavoidable, but for a simple wm it's overkill. See also: https://marc.info/?l=openbsd-ports&m=144822758614817&w=2
Remember the basic pledge idiom: setup -> pledge -> runtime > + main(int argc, char *argv[]) > + { > ++ if (pledge("stdio rpath unix dns proc exec prot_exec", NULL) == -1) > ++ die("pledge\n"); If you look in base, we only ever pledge after setlocale(3) at the earliest. But in this case, after setlocale(3) would still be too early in my opinion. Also, I would expect this pledge set to break starting a remote X session with dwm. > + if (argc == 2 && !strcmp("-v", argv[1])) > + die("dwm-"VERSION "\n"); > + else if (argc != 1) > +@@ -2132,7 +2134,11 @@ main(int argc, char *argv[]) > + if (!(dpy = XOpenDisplay(NULL))) > + die("dwm: cannot open display\n"); > + checkotherwm(); > ++ if (pledge("stdio rpath proc exec prot_exec", NULL) == -1) > ++ die("pledge\n"); Apparently, here it's still too early, dwm is still not entirely set up. What in setup() requires prot_exec? Why? Have you audited the X* and fontconfig libraries to make sure that no code path reachable from here (e.g. via config files, environment, what have you) can commit a pledge violation? > + setup(); > ++ if (pledge("stdio proc exec", NULL) == -1) > ++ die("pledge\n"); This is the pledge that really protects you long term, and that one is fine. > + scan(); > + run(); > + cleanup();