Repository navigation
Security
- Security Overview
- How Servy Protects Your Data
- Infiltration Guard: Local Import Enforcement
- Supply Chain and Trust
- The Servy Trust Boundary
- File Locations and Recovery
- Critical Warning: Machine Migration
- Best Practices
- Troubleshooting
Starting from v10.2, Servy is built for enterprise use. Every protection below is applied automatically, with no manual step and no sysadmin intervention:
-
100% per-service isolation between service accounts: each service account can reach only its own configuration and runtime state (through the
Servyservice, which checks the caller of every request) and only its own log folder (logs\services\<ServiceName>\). It cannot read or change the configuration database, the encryption key, Servy's own logs or the logs of any service running under another account. See The Servy Trust Boundary. - DPAPI and AES encryption: sensitive fields are encrypted with AES-256 and authenticated with HMAC-SHA256, under a key protected by DPAPI and bound to the machine. See How Servy Protects Your Data.
- Automatic ACLs: the vault, its binaries, its configuration files and each service's log folder get least-privilege access lists when a service is installed, and the grants are revoked when it is removed. See Executable Permission Hardening.
-
Automatic DACL on the named pipe: the
Servyservice's named pipe is open only to the accounts of the services Servy manages, and the list is rebuilt whenever a service is installed, moved to another account or removed. See Architectural Design & Runtime Permissions. - Signed binaries, SBOM and scanned releases. See Supply Chain and Trust.
Servy acts as a secure vault for your Windows service configurations. Servy encrypts sensitive data, including passwords, environment variables, and all execution arguments (Parameters, Password, EnvironmentVariables, FailureProgramParameters, PreLaunchParameters, PreLaunchEnvironmentVariables, PostLaunchParameters, PreStopParameters, and PostStopParameters), using industry-standard AES-256 encryption. If the database is compromised, your actual secrets remain unreadable text.
Starting in version 7.9, Servy uses a two-layer defense strategy to keep your secrets safe:
- The Locked Room (ACLs): Servy automatically restricts who can even view the Servy folders on your hard drive.
- The Machine-Unique Key (Dynamic Entropy): Servy ties your encryption key to the unique machine identity of your specific computer. If the files are moved to another PC, they cannot be decrypted without the machine-specific entropy stored in the originating system's registry.
You can verify that the "Locked Room" is active by checking the Access Control List (ACL) of the data directory. Run the following command in an elevated PowerShell window:
(Get-Acl "$env:ProgramData\Servy").Access | Select-Object IdentityReference, IsInherited, AccessControlType, FileSystemRightsWhat to look for in the output:
-
IdentityReference: You should see two principals:
NT AUTHORITY\SYSTEMandBUILTIN\Administrators. -
Note: The installer grants no personal user ACE, and removes any grant it finds for the installing account, because it always runs elevated (
PrivilegesRequired=admin). A third, per-user Full Control ACE appears only when the vault was created or re-hardened by a Servy process running non-elevated and not asSYSTEM(SecurityHelper.ApplySecurityRules). Since v10.2, custom service accounts do not appear here: they get access only to the log folder of each of their own services (logs\services\<ServiceName>\) and to the binaries and configuration files they read (see What Is Hardened). On 10.1 and earlier they appear here withModifyrights onceSet-ServyExePermissions.ps1has been run for them. -
IsInherited: This must be False for all entries. Servy explicitly breaks inheritance from the
%ProgramData%root to prevent "sideways" access from other applications or standard users. -
AccessControlType: This should be Allow. There should be no entries for broad identity groups such as
Everyone,Users, orAuthenticated Users, as these are surgically purged during the hardening phase. -
Executable Hardening Status: When inspecting individual core binaries under
%ProgramData%\Servy(such asServy.Service.exe), the executable permission hardening ensures that custom service runner accounts displayReadAndExecuterights rather than directory-inheritedModifyorFullControlrights. See this section for further details.
To reconcile this with the source code, auditors can refer to the following logic gates:
-
Inno Setup (
servy.iss): The installer executes withPrivilegesRequired=adminand explicitly grants permissions only toBUILTIN\AdministratorsandNT AUTHORITY\SYSTEM. It intentionally grants no personal user ACE because the elevated installer's user account is already fully covered by theAdministratorsgroup grant. -
Runtime (
SecurityHelper.cs): TheApplySecurityRulesmethod adds an explicit Full Control ACE for the current user only when the process is running non-elevated and is not the LocalSystem account (elevated admins and SYSTEM are already covered by the mandatory Administrators/SYSTEM ACEs). Any non-elevated runtime process invoking vault creation triggers this path.
While the root vault (%ProgramData%\Servy) has inheritance explicitly broken, all internal child folders such as db, security and logs are created with inheritance enabled relative to the vault root. This ensures the same "Locked Room" model (SYSTEM and Administrators, plus the installing user only in the non-elevated case described above) is maintained consistently throughout the entire data structure without redundant ACL writes.
Servy has overhauled its security model to be proactive rather than reactive.
In previous versions, Servy relied on Windows defaults for the %ProgramData%\Servy folder. In v7.9+, Servy takes control. Upon installation or startup, the application automatically performs the following actions:
-
Breaks Inheritance: Servy disconnects the folder from the open permissions of the parent drive.
-
Explicit Purge: Servy removes access for the
Users,Authenticated Users, andEveryonegroups. -
Restricted Entry: Only broad, unprivileged groups are removed -
Users,Authenticated UsersandEveryone.SYSTEMandAdministratorsare granted Full Control, and every other explicit entry on the folders Servy secures is removed, Allow and Deny alike; the installing user is preserved only in the non-elevated case (see the table below). This prevents Local Privilege Escalation: the risk of a standard user tampering with a service to gain Admin rights. -
Downward Inheritance: All subfolders and files within
%ProgramData%\Servyautomatically inherit these strict parent ACLs, ensuring new service directories, configurations, and logs remain locked down by default. -
Custom Permissions Are Not Preserved: On every elevated start of the Desktop App, Servy Manager or
servy-cli(Release builds), Servy removes every explicit entry for a principal other thanAdministratorsandLocal Systemfrom the vault and from every file and folder below it, and gives items owned by another principal toBUILTIN\Administrators. Service accounts recorded in the Servy database get their grants back straight afterwards (see What Is Hardened). An ACE you add by hand for any other account is removed at the next elevated start.
Servy uses the Windows Data Protection API (DPAPI) with an added security layer. To prevent binary analysis (where someone reads the source code to find a secret), Servy derives its encryption entropy from your computer's unique MachineGuid.
- Why it is safe: Encryption entropy is derived at runtime from your Windows Registry rather than hardcoded in the application binary.
-
Non-Portable: Because every computer has a different ID, your
aes_key.datfile is useless if copied to another machine.
If HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid is missing, unreadable, or restricted by registry permissions, Servy logs a critical security degradation error and falls back to deriving entropy from the host's Environment.MachineName. Under this fallback mode, renaming the host computer alters the entropy calculation and permanently breaks decryption for all protected configuration fields.
Caution
DYNAMIC ENTROPY DEPENDENCY & REGISTRY SENSITIVITY
Servy binds its DPAPI master key (%ProgramData%\Servy\security\aes_key.dat) to the system's MachineGuid. If MachineGuid is modified, deleted, corrupted, or blocked by registry permissions on an active installation, Servy will fail to unprotect its keying material; causing Servy Manager, servy-cli, and the background service to immediately fail decryption and halt operations.
If MachineGuid is missing or unreadable during initial key generation, Servy falls back to using the machine's hostname (Environment.MachineName) as its dynamic entropy source and logs a critical security degradation event. If the host is subsequently renamed while running under this fallback state, DPAPI decryption will also fail.
To recover from a decryption failure without re-importing service configurations:
- Restore the original
MachineGuidstring inHKLM\SOFTWARE\Microsoft\Cryptography. - Fix registry Access Control Lists (ACLs) if permission restrictions prevent Servy from reading
MachineGuid. - Revert the hostname if running under the fallback state.
- Otherwise, if a valid pre-existing dump archive is available, purge the stale vault (
%ProgramData%\Servy\dband%ProgramData%\Servy\security) and restore configurations usingServy-Restore.ps1(see Backup/Restore & VM Cloning).
To adhere to strict cryptographic best practices, Servy uses HKDF (RFC 5869) to derive independent sub-keys from your master key. Distinct info context strings (V2_AES_ENCRYPTION and V2_HMAC_AUTHENTICATION) give the encryption and authentication sub-keys domain separation, ensuring neither can be derived from or substitute for the other.
Servy protects sensitive data using DPAPI-derived keying material combined with machine-specific registry entropy. Authenticated encryption (HMAC-SHA256 + AES-256-CBC) ensures both confidentiality and tamper detection, preventing bit-flipping attacks by refusing to decrypt any modified payload.
Security doesn't stop at the hard drive. To protect against advanced memory scraping attacks, Servy securely handles secrets in RAM. The SecureData class implements IDisposable and utilizes CryptographicOperations.ZeroMemory() to wipe every sensitive buffer as soon as it is no longer needed:
- Transient Data: Plaintext and ciphertext buffers are zeroed immediately after each encryption/decryption call.
- Initialization Material: The master key clone passed during construction is wiped as soon as sub-keys are derived.
-
Key Material: All active sensitive buffers are securely zeroed upon the object's disposal. This includes the two HKDF-derived V2 sub-keys required for modern AES encryption and HMAC authentication. (Note: The two legacy V1 buffers, used for master key cloning and static IV retention, remain unallocated in shipped production builds as
AllowLegacyV1Decryptionis permanently disabled at compile-time).
Unlike standard array clearing methods, this approach ensures that the memory wipe is never elided by the JIT compiler's release optimizations, significantly reducing the window of opportunity for an attacker to extract keying material from a memory dump.
While Servy supports CLI flags for configuration convenience (e.g., --password, --envVars, --params), passing sensitive data via command-line arguments is insecure. Command-line arguments are visible to any user or process able to enumerate the process list (e.g., Get-Process, pslist, or Event Tracing for Windows) and are often recorded in shell history files and system audit logs.
Starting in v8.5, Servy provides two secure alternatives to handle sensitive data:
- Environment Variables (Recommended for per-service secrets): For each sensitive field, Servy supports an associated environment variable. Servy reads these variables transparently at install time, ensuring the secret never touches the process argument string.
-
Import Configuration (Recommended for complex deployments): Use the
importcommand with an XML or JSON configuration file. This keeps sensitive values entirely out of the command line and allows for structured, version-controlled configuration management.
The following parameters are considered sensitive and should be provided via environment variables (v8.5+) or configuration files:
| Parameter | Environment Variable | Description |
|---|---|---|
--password |
SERVY_PASSWORD |
Windows service account password. |
--params |
SERVY_PROCESS_PARAMETERS |
Command-line arguments for the service process. |
--envVars |
SERVY_ENVIRONMENT_VARIABLES |
Environment variables for the service process. |
--failureProgramParams |
SERVY_FAILURE_PROGRAM_PARAMETERS |
Arguments for the failure recovery program. |
--preLaunchParams |
SERVY_PRE_LAUNCH_PARAMETERS |
Arguments for the pre-launch executable. |
--preLaunchEnv |
SERVY_PRE_LAUNCH_ENVIRONMENT_VARIABLES |
Env vars for the pre-launch executable. |
--postLaunchParams |
SERVY_POST_LAUNCH_PARAMETERS |
Arguments for the post-launch executable. |
--preStopParams |
SERVY_PRE_STOP_PARAMETERS |
Arguments for the pre-stop executable. |
--postStopParams |
SERVY_POST_STOP_PARAMETERS |
Arguments for the post-stop executable. |
--heartbeatUrl |
SERVY_HEARTBEAT_URL |
Heartbeat ping URL. Monitoring endpoints such as https://hc-ping.com/<uuid> are capability URLs: anyone who learns the path can fake a "service is alive" ping. Servy masks the URL in its own logs. Available from v10.4; earlier versions ignore the variable, so pass --heartbeatUrl there. |
# Set the secrets in the process-level environment
$env:SERVY_PASSWORD = 'p@ssw0rd_123!'
$env:SERVY_ENVIRONMENT_VARIABLES = 'API_KEY=secret_key_123;DB_URL=...'
# Install the service (omit sensitive flags)
servy-cli install --name="MySecureService" --path="C:\App\app.exe" --user="DOMAIN\svc_account"
# Clear variables immediately after use
Remove-Item Env:SERVY_PASSWORD
Remove-Item Env:SERVY_ENVIRONMENT_VARIABLESImporting service configurations from Universal Naming Convention (UNC) paths or through redirected paths (such as symbolic links or junctions) poses severe security risks. These techniques are designed to bypass system trust boundaries and expose the application execution layer to malicious configuration injection.
To preserve system integrity, the import pipeline explicitly blocks non-local paths. The primary attack vectors mitigated by this enforcement include:
-
Attacker-Controlled Configuration Injection: UNC targets (e.g.,
\\attacker\share\evil.xml) allow a remote adversary to host a malicious configuration file on an infrastructure node under their direct control. If ingested, an attacker can inject arbitrary executable paths, unauthorized parameters, or unverified environment variables, effectively hijacking the service's runtime behavior. - Path Redirection Attacks: By leveraging filesystem symbolic links, directory junctions, or specialized Win32 reparse points, an attacker can manipulate the path resolution mechanics. This can trick the engine into reading from an entirely different backend target than intended, exposing sensitive files or pulling parameters from unexpected network locations.
-
Privilege Escalation and System Integrity: Because the engine performs administrative elevation validation checks to operate securely, it possesses high-privilege access to the local machine. If an import task is manipulated into processing files from protected operating system directories (such as the
WindowsorSystem32namespaces), it can facilitate unintended system-level file access or manipulation. -
Network-Based Mapping Bypasses: Virtual local paths - including mapped network drives (e.g.,
Z:\config.json) or local DOS device substitutions (subst) - frequently mask underlying remote storage volumes. These targets inherently lack the rigid security boundaries of localized storage hardware, introducing network-level interception vectors.
To counter these vectors, the engine pipes all configuration paths through a strict, sequential validation chain before any file access occurs across the CLI or GUI interfaces:
-
Explicit UNC Inspection: Rejects any raw path strings starting with standard network prefixes (
\\) or parsing as a remote URI. -
Drive Interface Queries: Evaluates the target volume via
DriveInfoto proactively block network-backed logical drive letters. - Reparse Point Ancestor Walks: Recursively traces the full directory tree to verify that no parent or sibling paths utilize symbolic links or directory junctions.
- File-Level Symlink Evaluation: Directly inspects filesystem attributes to confirm the target file is a physical, non-symbolic entity.
-
Reserved Device Blocks: Prevents spoofing attempts using legacy system device designations (e.g.,
CON,PRN,AUX). - Protected System Directory Fencing: Prevents configuration loading out of primary administrative operating system paths.
-
Win32 Kernel Handle Finalization: Opens a temporary restricted read handle and resolves the target's final canonical path via
GetFinalPathNameByHandle, ensuring junctions, subst mappings, and virtual devices cannot conceal a UNC target.
Security requires transparency. You should not have to guess if Servy is safe.
- Digitally Signed: All executables and installers are signed by SignPath. This proves the code has not been altered since it left the build server.
- SBOM (Software Bill of Materials): Servy releases include a full inventory of every component and dependency in the CycloneDX format.
- Vulnerability Scanning: GitHub Dependabot raises an alert whenever a published advisory matches one of the dependencies.
- Scanned Releases: Release binaries are scanned on VirusTotal, and false-positive reports are submitted to Microsoft Security Intelligence and affected AV vendors.
Starting from v10.2, Servy uses per-service security isolation. Before v10.2, every service account shared a single trust boundary: each one could read and change the shared configuration database, read the encryption key, and read or delete the logs and recovery state of every other service. v10.2 removes that shared tier. A service account can now reach only its own configuration, its own runtime state and the log folders of its own services (logs\services\<ServiceName>\).
v10.2 adds a background Windows service, Servy (Servy.Host.exe). It runs as LocalSystem and is the only process that opens the configuration database and the encryption key on behalf of a running service. Each Servy.Service.exe still runs under the identity of your configured service account, but it no longer opens db\Servy.db or security\aes_key.dat itself. It asks the Servy service for what it needs over a local named pipe (\\.\pipe\SERVY_HOST_IPC_PIPE):
- Reading its configuration: the service receives its own decrypted configuration, and nothing else. The password of the service account is never sent.
-
Writing its runtime state: the process ID of the wrapped application, the active
stdout/stderrlog paths and the stop timeout in effect are written for it. -
Restart attempts: the restart-attempt counter of the recovery feature is stored in
Servy.dband read and written through the pipe. Before v10.2 it was kept in text files in%ProgramData%\Servy\recovery\; that folder is imported into the database once, by the database migration of the upgrade, and deleted once its counters have been imported.
The Servy service checks every request:
-
Who may connect: the pipe is created with a protected access list that grants
NT AUTHORITY\SYSTEMandBUILTIN\AdministratorsFull Control, grants the accounts of the services Servy manages Read/Write only. Network logons are supported: a local process whose token comes from a network logon (for exampleservy-cliin a PowerShell remoting or WinRM session) is checked like any other. The pipe is local only: it is created withPIPE_REJECT_REMOTE_CLIENTS, so a client on another computer cannot open it, and theServyservice also refuses any request from one. The list is rebuilt whenever a service is installed, reinstalled under another account or removed, and is applied to the pipe immediately, without restarting theServyservice, so an account loses access to the pipe when its last service goes away. -
What a caller may ask for: a service account may only read or update the service it is running. The
Servyservice compares the process ID of the caller (GetNamedPipeClientProcessId) with the process ID the Service Control Manager reports for the service named in the request, and refuses the request when they differ. Administrators andSYSTEMare not restricted. -
Who the client talks to: before sending anything,
Servy.Service.exechecks that the process serving the pipe is the one the Service Control Manager reports for theServyservice, so another process cannot squat the pipe name and serve a forged configuration.
Every service Servy installs depends on the Servy service, so Windows starts it first. The Desktop App, Servy Manager and servy-cli extract Servy.Host.exe into %ProgramData%\Servy, install the Servy service when it is missing (startup type Automatic), start it when it is not running, and add the dependency to services installed by an older version. When the Servy service is registered with another executable than the one they extracted (after switching between the .NET 10 and the .NET Framework 4.8 build, which names it Servy.Host.Net48.exe), they stop the running Servy services and the Servy service, point the service at their own executable, and start them again. When Servy.Service.exe or Servy.Host.exe has to be updated, they stop the running Servy services and the Servy service, replace the binaries, then start them again. The name Servy is reserved and cannot be used for one of your own services.
Servy.Service.exe writes its own log to the folder of its service, %ProgramData%\Servy\logs\services\<ServiceName>\Servy.Service.log, and Servy.Restarter.exe, which it launches, writes Servy.Restarter.log to the same folder. A character a folder name cannot hold (< > : " / \ | ? * and control characters), a trailing dot or space, a reserved device name such as CON, and the characters % and ~ are percent-encoded in the folder name (My:Service logs to logs\services\My%3AService\), so two services never share a folder; a name whose encoded form is longer than 100 characters is shortened to its first 64 encoded characters, followed by ~ and 16 hexadecimal characters of a hash of the name. Before v10.2 the log of every service was logs\Servy.Service.log. On an upgrade that file is left where it is, in logs\, for the administrators: it is not moved or deleted, no service writes to it any more, and no service account can read it, since it may hold the entries of every service. Delete it once you no longer need it.
A service account gets the least privilege its services need: nothing on the vault root, nothing in db\, security\ and logs\, write access only in the log folder of each of its own services (logs\services\<ServiceName>\), Read & Execute on the binaries and Read on the configuration files. Starting from v10.2, Servy applies this hardening itself. It is built into the Desktop App, Servy Manager, servy-cli and the PowerShell module, so it works wherever they run, including a portable servy-cli.exe copied on its own. No script and no manual step are needed.
Note
AUTOMATIC SINCE v10.2
Servy hardens the vault for an account:
- when it installs a service under an account other than Local System (including
LocalService,NetworkService, virtual accounts and gMSAs), and when it reconfigures an existing service under such an account; - again for every account a service runs under, on every elevated start of the Desktop App, Servy Manager or
servy-cli, whether or not a binary was extracted, because the vault is purged of non-administrative entries first and each account is granted its access back right after.
Local System, the BUILTIN\Administrators group and its members are left untouched: they keep Full Control, so there is nothing to restrict. The outcome is written to the Servy log. If the hardening cannot be applied, the service is still installed and the log says why; installing the service again re-applies it.
Path under %ProgramData%\Servy
|
Service account's rights |
|---|---|
| The vault folder itself | None. A grant a previous version wrote there is removed. |
db\, security\
|
None. The account's explicit entries on the folders and on the files directly inside them (Servy.db, aes_key.dat, ...) are removed. Only the Servy service, running as LocalSystem, opens them. |
logs\ and everything under it, other than the account's own service log folders |
None. The account cannot list, read, write or delete the logs of Servy, the shared Servy.Service.log that versions before v10.2 wrote to logs\, or the log folder of any service it does not run. The account's explicit entries on every file and folder under logs\ are removed. |
logs\services\<ServiceName>\, for each service the account runs |
On the folder: List and Create Files (creating the log, and the new file of a log rotation), never Delete (it cannot rename or delete the folder). On the files in it: Read, Write, Delete (log rotation and pruning). The folder is created if missing. |
Servy.Host.exe / Servy.Host.Net48.exe
|
None. The service account cannot read, write or execute the host binaries. |
*.exe and *.dll: Servy.Service.exe, Servy.Service.CLI.exe, Servy.Restarter.exe, handle64.exe / handle64a.exe (.NET Framework 4.8 build: the *.Net48.exe binaries, handle64.exe and every *.dll) |
Read & Execute |
appsettings.host.json / Servy.Host.Net48.exe.config
|
None. The service account cannot read the host configuration file. |
*.json and *.config: appsettings.service.json, appsettings.restarter.json (.NET Framework 4.8 build: the *.exe.config files) |
Read only |
The service account needs no right on logs\ or logs\services\ to reach logs\services\<ServiceName>\: Windows grants every account the Bypass traverse checking privilege by default, so a full path can be opened without listing its parents.
Accounts are compared by SID, so a service account that runs several services (written .\user for one and MACHINE\user for another, for example) is granted the folders of all of them, and installing one more service under it keeps the folders of the others. Two services that run under the same account share that account's identity, so they can read each other's logs; give each service its own account when their logs must be isolated from each other as well.
Each hardened file stops inheriting from the vault, is owned by BUILTIN\Administrators, and keeps Full Control for NT AUTHORITY\SYSTEM and BUILTIN\Administrators (well-known SIDs, so it works on any Windows language). Explicit grants to Everyone, Users and Authenticated Users are removed. Hardening one service account never removes another service account's entries, but the next elevated start removes explicit entries for any principal that is neither Administrators, Local System nor a service account in the database. The access is taken back when a service goes away: after a service is uninstalled, or reinstalled under another account, Servy always removes the former account's entries from that service's log folder, logs\services\<ServiceName>\ (the folder and its logs are kept, for the administrators). When no other service in the database still runs under that account (the same account written as .\user or MACHINE\user counts as one), Servy also removes the account's explicit entries from the vault root, db\, security\, every file and folder under logs\ and under the legacy recovery\ folder (while it is still there), and every hardened file, and revokes its access to the named pipe. A failure is logged and does not fail the uninstall. The service account can delete nothing outside the log folders of its own services, and no folder. A file that is a symbolic link or a junction, or that has more than one hard link, is left untouched and reported as a failure. A binary that is not present yet (for example Servy.Service.CLI.exe when only the Desktop App has been used) is hardened once it is extracted.
When an existing installation is upgraded to v10.2, the grants that earlier versions gave the service accounts on db\, logs\, recovery\, Servy.db and aes_key.dat are removed, and the log folder of each service is created and granted to its account, the next time the vault is hardened for each account, which happens on the first elevated start of the Desktop App, Servy Manager or servy-cli after the upgrade. The recovery\ folder itself is imported into Servy.db once, by the database migration of the upgrade, and deleted once its counters have been imported. A counter file is imported whatever its owner, so a service that ran under its own account before the upgrade keeps its counter. A counter file that is a symbolic link or junction, or has more than one hard link, is skipped with a security warning in the log, and is not deleted; the folder is then kept.
Since v10.2, Servy.Restarter.exe is extracted by the Desktop App, Servy Manager and servy-cli rather than by the service, so the service account needs no Delete right on it.
Behavior Once Hardened:
The hardening breaks ACL inheritance on Servy's core binaries and restricts explicit execution rights, so a custom service account added later does not inherit rights on the hardened binaries from the %ProgramData%\Servy parent directory. Servy hardens each account when a service is installed under it; an account that is only granted permissions on the vault root by hand would be denied execution rights on Servy.Service.exe by the Windows Service Control Manager (SCM) (ERROR_ACCESS_DENIED).
The executable permission hardening protects your deployment against:
-
Unprivileged Binary Replacement & Tampering: Prevents a compromised service process or runner account from overwriting core binaries (
Servy.Service.exe,Servy.Restarter.exe,Servy.Host.exe, etc.) to execute arbitrary code under elevated administrative contexts. -
DLL Hijacking: Blocks rogue or compromised non-admin identities from planting or replacing shared
.dlldependencies within the application vault directory. -
Local Privilege Escalation (LPE): Ensures that service runner privileges cannot be leveraged to gain unauthorized write access over executable components executed by
SYSTEMorAdministrators. -
Configuration Database Access: A service account cannot open
db\Servy.dbat all. It can neither read the configuration of other services nor change, replace or delete the database. -
Encryption Key Access: A service account cannot open
security\aes_key.dat, so it can neither read nor replace the key every Servy process trusts. - Cross-Service Log Access: A service account cannot read, write or delete Servy's own logs or the log folder of any service that runs under another account.
Important
Administrative Service Accounts: Use a dedicated, unprivileged service account. Because Windows evaluates all group SIDs attached to an access token and Allow ACEs do not subtract rights, any member of BUILTIN\Administrators inherently keeps FullControl over the hardened files through group membership, which is why Servy skips the hardening for such an account. Membership through a nested group (for example a domain group added to the local Administrators group) cannot always be detected; Servy then applies the hardening and logs that it could not rule it out.
Note
Starting from v9.7, Servy automatically captures and preserves existing explicit Access Control Lists (ACLs) across atomic file updates for *.exe and *.dll files located in %ProgramData%\Servy. Once configured, your Read & Execute permission boundaries will persist automatically across application updates and embedded resource re-extractions.
Servy 10.1 and earlier do not harden the vault automatically. Run Set-ServyExePermissions.ps1 from an Elevated (Administrator) PowerShell session for every custom account (or a group containing it) that runs a Servy service. Without it, the account has no access to the vault, or, if the vault was granted Modify by hand, it keeps inherited Modify rights on the core binaries and can replace or tamper with code executed by SYSTEM and Administrators.
-
Servy v9.7 to 10.1: the script is located in
%ProgramFiles%\Servyafter installation, and in the root of the portable package. That copy does not grant the vault access: with it, first grant the account Modify on%ProgramData%\Servy(inherited by subfolders and files), or use the version linked below. -
Latest script for these versions (it keeps the Delete right on
Servy.Restarter.exethat these versions need, because their service extracts the restarter itself):
# LocalService account
.\Set-ServyExePermissions.ps1 -TargetAccount "LocalService"
# Local account / relative notation
.\Set-ServyExePermissions.ps1 -TargetAccount ".\user_svc"
# Active Directory domain user or group
.\Set-ServyExePermissions.ps1 -TargetAccount "MYDOMAIN\svc-servy"
# Group Managed Service Account (gMSA)
.\Set-ServyExePermissions.ps1 -TargetAccount "CORP\app-gmsa$"The script applies the hardening of those versions: write access to db\, logs\ and recovery\, Read & Execute on the binaries and Read on the configuration files. It does not cover aes_key.dat. Re-running it for another account preserves the permissions of the accounts it hardened before. If Servy.db is recreated (for example after purging db\ on a cloned VM), re-run it.
Tip
Managing Multiple Service Accounts: On these versions, if you manage dozens of custom runner accounts on a single server, consider creating a dedicated local or domain security group (e.g., Servy-ServiceRunners), running Set-ServyExePermissions.ps1 -TargetAccount "Servy-ServiceRunners" once, and adding each new service account to that group.
Important
Prior to v9.7, ACLs for *.exe and *.dll files inside %ProgramData%\Servy are not preserved across atomic updates. Upgrading or re-extracting binaries on older versions will cause new files to inherit default directory permissions (Modify), requiring Set-ServyExePermissions.ps1 to be re-run after each update to restore Read & Execute hardening.
-
Per-Service Isolation: Each service account reaches only its own configuration and runtime state, through the
Servyservice, and only the log folders of its own services. It cannot read the configuration database, the encryption key, the logs of services running under other accounts or Servy's own logs, and it cannot change the records of another service. -
Per-Service Log Folders: Each service writes its wrapper and restarter logs to its own folder,
logs\services\<ServiceName>\, which only its own account (plusSYSTEMandAdministrators) can reach. Thestdout/stderrlogs of your application are written wherever you configure them and are not affected. -
The
ServyService Must Run: A service cannot start without its configuration, so every Servy service depends on theServyservice. If it is stopped or disabled, the Desktop App, Servy Manager andservy-clistart it again on their next run; you can also start it fromservices.msc. -
Zero Trust Isolation: Per-service isolation protects co-located services from each other's service accounts. It does not protect against an administrator or
SYSTEM, and it does not isolate the applications themselves (files, network, registry). If your security architecture requires strict multi-tenant isolation, services should be deployed across distinct Virtual Machines, isolated OS installations, or Windows Containers.
| Identity | Access Level | Managed By | Description |
|---|---|---|---|
| SYSTEM | Full Control | Servy (Automatic) | Required for local system service host management. |
| Administrators | Full Control | Servy (Automatic) | Required for administrative configuration. |
| Installing User | Full Control | Servy (Automatic) | Preserved for operational continuity when installed non-elevated. |
| Custom Service Accounts | None on the vault root, db\, security\ and logs\; write access to the log folder of each of their own services (logs\services\<ServiceName>\) only, Read & Execute on the binaries, Read on the configuration files (see What Is Hardened) |
Servy (Automatic, v10.2+) | Granted by Servy when a service is installed under a non-SYSTEM identity. On 10.1 and earlier, Modify on the vault, granted by Set-ServyExePermissions.ps1 run by hand. |
| Standard Users | None | Servy (Automatic) | Explicitly purged on startup to prevent standard user tampering. |
Note
In Servy's ACL hardening context, Standard Users refers to broad identity groups including Everyone, Users, or Authenticated Users.
Note
The installing user ACE is added by SecurityHelper.ApplySecurityRules only when the current process identity is neither SYSTEM nor an Administrator. An elevated (admin) install adds no ACE of its own: that account is already covered by the BUILTIN\Administrators grant.
Important
If you configure a service to run under a custom local or domain Service Account (or gMSA), that account needs write access to the log folder of its service (logs\services\<ServiceName>\), read access to the binaries and configuration files, and access to the Servy service's named pipe. Starting from v10.2 Servy grants exactly that automatically when it installs the service; on 10.1 and earlier, run Set-ServyExePermissions.ps1 for the account, which grants Modify on %ProgramData%\Servy. Without that access, the service runner will fail to load its configuration or write its logs. See Executable Permission Hardening section for details.
Your master encryption keys are stored here:
-
Database:
%ProgramData%\Servy\db\Servy.db(opened only by theServyservice, Servy Manager, the Desktop App andservy-cli) -
Key:
%ProgramData%\Servy\security\aes_key.dat -
IV:
%ProgramData%\Servy\security\aes_iv.dat
The aes_iv.dat file holds the static IV used by the legacy v1 cipher format (Servy < 6.5). Servy 6.5+ uses a per-message random IV embedded in the ciphertext, so the static IV is no longer used to encrypt or decrypt anything in current builds - v1 decryption is permanently disabled (AllowLegacyV1Decryption = false) to mitigate downgrade attacks. While disabled, the file is not read on service start and is not loaded into memory; the entire load path is compiled out via the AllowLegacyV1Decryption constant, so the runtime no longer creates aes_iv.dat on fresh installs; the file is only present on machines that were first set up by an older (pre-gating) build, where it should be retained - do not delete it. To migrate records written by a pre-6.5 build, export them with a v1-compatible Servy version and import the resulting file into the current version; they will be re-encrypted as v2.
Because the encryption is tied to your specific Windows installation, you cannot copy the .dat files to a new server.
To move Servy to a new PC, use Servy-Dump.ps1 and Servy-Restore.ps1 to export and import your service configurations. If you attempt to copy the .dat files to a new machine, Servy will fail to decrypt any of the sensitive fields.
-
Backup the Whole Servy Data Folder: Before doing a Windows Reset or Refresh, back up the entire
%ProgramData%\Servy\tree. The keys (security\*.dat) and the encrypted configuration database (db\Servy.db) must be restored together - keys alone cannot decrypt anything, and the database alone cannot be decrypted without the matching keys. - Use Managed Accounts: When possible, run services under Group Managed Service Accounts (gMSA) for the best balance of security and ease of use.
-
Audit Access: Periodically check the Security tab of the
%ProgramData%\Servyfolder to ensure no unauthorized users have been added manually.
-
Access Denied on Startup: This usually means the account running the service does not have permissions to the
%ProgramData%\Servyfolder. Refer to the Permissions Table above. -
Service Cannot Load Its Configuration (v10.2+): Check that the
Servyservice is installed and running (sc.exe query Servy), then read%ProgramData%\Servy\logs\Servy.Host.logand%ProgramData%\Servy\logs\services\<ServiceName>\Servy.Service.log. Running the Desktop App, Servy Manager or anyservy-clicommand reinstalls and starts theServyservice if needed; reinstalling the service re-grants its account access to the named pipe. The one exception is a service namedServythat does not runServy.Host.exeorServy.Host.Net48.exe, for example one installed under that name by an earlier version: Servy leaves it untouched and reports an error that names it, so the host service is not installed and the Servy services cannot load their configuration. Export that service, uninstall it, and import it under another name, then run any Servy command again. The same happens when the executable of the existingServyservice cannot be read. -
Decryption Error: This happens if the
.datfiles were moved from another computer, restored from an image, corrupted, or if the WindowsMachineGuidwas altered. Servy then refuses to save any service whose encrypted fields (Password,Parameters,EnvironmentVariables,PreLaunchEnvironmentVariablesand the hook parametersPreLaunchParameters,PostLaunchParameters,PreStopParameters,PostStopParameters,FailureProgramParameters) cannot be decrypted, so they cannot be re-entered in place, and it never replaces an existingaes_key.dat. To recover:- Do not delete or replace
aes_key.datoraes_iv.dat: a new key can never decrypt the existing database. - Restore
%ProgramData%\Servy\security\aes_key.datandaes_iv.datfrom a backup of this machine, then restart Servy. - Otherwise, copy
%ProgramData%\Servy\db\Servy.dbback to the original machine and export the service configurations to XML or JSON there. You can useServy-Dump.ps1to perform the batch export. - Only then, on this machine, back up and delete
%ProgramData%\Servy\securityand%ProgramData%\Servy\db, and import the exported configurations (per Critical Warning: Machine Migration). Usernames and passwords are not exported and must be re-entered. You can useServy-Restore.ps1to perform the batch import.
- Do not delete or replace
Servy v7.9+ automates the routine parts of Windows security - Access Control Lists (ACLs) and machine-bound key derivation - so a locked-down setup is the default rather than a manual checklist.
Questions? Check the full Troubleshooting Guide or open a GitHub Issue to get help from the community and developers.
Copyright © Akram El Assas. All rights reserved.
Getting Started
Core Suite
Configuration & Features
- Advanced Configuration
- Logging & Log Rotation
- Health Monitoring & Recovery
- Environment Variables
- Service Dependencies
- Export / Import Services
Lifecycle Hooks
Automation & Production
- Servy Automation & CI/CD
- Embedding in Custom Installers
- Integration with Monitoring Tools
- Service Event Notifications
- Backup / Restore & VM Cloning
Reference & Support