Repository navigation
[FEATURE] A --harden-files verb: the service knows the correct ACL and cannot apply it, and only the installer ever does #2352
Description
The service computes the correct ACL, detects when the real one is wrong, and prints the remediation — but the only thing that ever applies it to an existing install is install-darling.ps1. A box set up any other way, or whose ACLs drifted, leaves the operator hand-typing three icacls lines out of a log message.
Seen on a real box today
The PostgreSQL monitoring host was created with sc create directly rather than through install-darling.ps1, so the installer's section 4b hardening never ran. Every service start since has logged this, correctly:
[ERROR] Could not restrict the ACL on C:\PerformanceMonitorDarling\darling.json
(owner is BUILTIN\Administrators; readable by BUILTIN\Users)
(Attempted to perform an unauthorized operation.)
... From an ELEVATED prompt: icacls "..." /inheritance:d then /remove:g "BUILTIN\Users"
then /grant "NT SERVICE\PerformanceMonitor Darling:(F)"
[CRIT ] C:\PerformanceMonitorDarling\darling.json is READABLE by Users/Authenticated Users/Everyone.
It holds every monitored server's encrypted password plus the MCP and web access tokens...
Confirmed against the file itself: BUILTIN\Users: ReadAndExecute present, AreAccessRulesProtected = False, owner BUILTIN\Administrators. Same on C:\ProgramData\PerformanceMonitorDarling and the credential files under it.
The diagnostic half is genuinely good and I do not want to change it. It named the file, the owner, the exposure, why a restart will not help, and the exact commands. DarlingWorker.TryHardenConfigFile's comment explains the reasoning — that a log line saying the ACL is wrong is not the same as knowing what to type — and it is right.
The gap
DarlingFileSecurity.HardenFile already encodes the correct DACL. IsReadableByOrdinaryUsers already verifies the result. The service cannot call them successfully because a virtual service account has neither WRITE_DAC on a file it does not own nor the privilege to take ownership — as the log says, and as the code comments already anticipated.
So the capability exists and the authority does not, and nothing lets an operator who has the authority invoke it. TryHardenExportedSecret (DarlingCliCommands.cs:1174) is the closest thing and it only covers a freshly exported file.
Proposal
PerformanceMonitor.Darling.Service.exe --harden-files, run from an elevated prompt:
- Hardens
darling.json(allowInteractiveRead: true— the Viewer and CLI verbs read it as the interactive operator), itsdarling.json.bak-*siblings (false), the ProgramData directory, and the credential files under it (false) - Verifies and reports per file rather than claiming success. "We tried" is not "the secret is not readable" — a distinction
TryHardenExportedSecret's own doc comment already makes - Exit code reflects whether anything is still readable by ordinary users, so it is usable in a provisioning script
- Idempotent, so it is safe on a healthy box and can just live in a runbook
That is mostly wiring: the DACL construction, the verification and the file list all exist. install-darling.ps1 section 4b then becomes a caller rather than a second implementation of the rule — the same anti-drift move #2343 made for the install-location check, which found real bugs in the PowerShell/C# pair precisely because they had been written twice.
Also worth considering
The install-location diagnostic from #2343 fires on an unreadable tree. This is the opposite failure — a tree readable by too many — and it has no equivalent startup verdict beyond the per-file CRITICAL. Both are "the install is in a place that hurts you"; they may deserve one report.
Not urgent for 3.5.0
No customer is blocked: the installer does the right thing on the documented path, and the log tells anyone off that path exactly what to type. This removes a manual step and a chance to typo an ACL, which is worth doing but not worth holding a release for.
Activity
Add --harden-files, the actor that can apply the ACLs the service onl…
Add --harden-files, the actor that can apply the ACLs the service onl…
Add --harden-files, the actor that can apply the ACLs the service onl…
Add --harden-files, the actor that can apply the ACLs the service onl…
erikdarlingdata commentedon Aug 19, 2026
Shipped in #2358.
--harden-filesre-applies the ACLs from an elevated prompt, verifies every target afterwards rather than claiming success, and exits non-zero if anything is still readable by ordinary users — so it can gate a provisioning script.darling.jsonis the only target that keeps an INTERACTIVE read ACE (the Viewer and CLI verbs run as the operator and must read it); the.bak-*siblings, the store directory and the DPAPI credentials get none, because nothing reads a backup.Two deliberate softnesses: a config that will not load is a warning rather than a stop — an unreadable
darling.jsonis the failure this exists to repair, so refusing to run without it would refuse exactly when it is needed — and missing targets are skipped quietly, since a BYO-Postgres install has no managed credential files.Describe what --harden-files actually verifies (#2373)