Skip to content

Security

aelassas edited this page Aug 22, 2026 · 105 revisions

Table of Contents

  1. Security Overview
  2. How Servy Protects Your Data
    1. Automatic Directory Hardening (ACLs)
    2. Machine-Unique Encryption (Dynamic Entropy)
    3. Cryptographic Key Derivation (HKDF)
    4. Authenticated Encryption (v6.5+)
    5. In-Memory Defense (Memory Zeroing)
    6. Sensitive Command-Line Arguments & Service Account Credentials
  3. Infiltration Guard: Local Import Enforcement
  4. Supply Chain and Trust
  5. The Servy Trust Boundary
    1. Architectural Design & Runtime Permissions
    2. Executable Permission Hardening (Mandatory)
      1. Script Availability
      2. Hardening Utility Usage
    3. What This Means for Your Deployment
    4. Automatic Permissions Table (v7.9+)
  6. File Locations and Recovery
  7. Critical Warning: Machine Migration
  8. Best Practices
  9. Troubleshooting

Security Overview

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.

The Double-Lock System

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, FileSystemRights

What to look for in the output:

  • IdentityReference: You should typically see three principals: NT AUTHORITY\SYSTEM, BUILTIN\Administrators, and the specific user account that installed Servy (or custom service runner accounts added manually).

  • Note: The installer and the SecurityHelper class grant the current user Full Control as a "Manual Key" to ensure operational continuity. If the installation was performed strictly by a process already running as SYSTEM, only the first two will appear. Custom non-administrative service accounts will appear here once granted Modify rights.

  • 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, or Authenticated Users, as these are surgically purged during the hardening phase.

  • Executable Hardening Status: When inspecting individual core binaries under %ProgramData%\Servy (such as Servy.Service.exe), running Set-ServyExePermissions.ps1 ensures that custom service runner accounts display ReadAndExecute rights rather than directory-inherited Modify or FullControl rights. See this section for further details.

Implementation Context for Auditors

To reconcile this with the source code, auditors can refer to the following logic gates:

  • Inno Setup (servy.iss): The ShouldAddCurrentUser check ensures the interactive installer's account is added to the folder ACL.
  • Runtime (SecurityHelper.cs): The ApplySecurityRules method adds an explicit Full Control ACE for the current user only when that user is neither the LocalSystem account nor a member of the Administrators group (admins and SYSTEM are already covered by the mandatory Administrators/SYSTEM ACEs). The interactive installer's account ACE is added separately by the Inno Setup ShouldAddCurrentUser step and preserved by ApplySecurityRules.

Subdirectory Inheritance Note

While the root vault (%ProgramData%\Servy) has inheritance explicitly broken, all internal child folders such as recovery, db, and security are created with inheritance enabled relative to the vault root. This ensures the three-principal "Locked Room" security model is maintained consistently throughout the entire data structure without redundant ACL writes.

How Servy Protects Your Data

Servy has overhauled its security model to be proactive rather than reactive.

1. Automatic Directory Hardening (ACLs)

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, and Everyone groups.

  • Restricted Entry: Only SYSTEM and Administrators are allowed in. 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%\Servy automatically inherit these strict parent ACLs, ensuring new service directories, configurations, and logs remain locked down by default.

  • Custom Permissions Preserved (with caveat): Explicit Allow ACEs you have added for named identities are retained. Any Allow rule targeting the broad groups Users, Authenticated Users, or Everyone is removed on every run. Deny rules for those broad groups are left in place; only Deny rules targeting Administrators, LocalSystem, or the installing user are removed as an anti-squatting measure.

2. Machine-Unique Encryption (Dynamic Entropy)

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.dat file is useless if copied to another machine.

3. Cryptographic Key Derivation (HKDF)

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.

4. Authenticated Encryption (v6.5+)

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.

5. In-Memory Defense (Memory Zeroing)

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 AllowLegacyV1Decryption is 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.

6. Sensitive Command-Line Arguments & Service Account Credentials

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.

The Preferred Methods

Starting in v8.5, Servy provides two secure alternatives to handle sensitive data:

  1. 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.
  2. Import Configuration (Recommended for complex deployments): Use the import command 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.

Sensitive Fields Reference

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.
PowerShell Example:
# 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_VARIABLES

Infiltration Guard: Local Import Enforcement

Importing 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 Windows or System32 namespaces), 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.

Mitigation: Defense-in-Depth Pipeline

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:

  1. Explicit UNC Inspection: Rejects any raw path strings starting with standard network prefixes (\\) or parsing as a remote URI.
  2. Drive Interface Queries: Evaluates the target volume via DriveInfo to proactively block network-backed logical drive letters.
  3. Reparse Point Ancestor Walks: Recursively traces the full directory tree to verify that no parent or sibling paths utilize symbolic links or directory junctions.
  4. File-Level Symlink Evaluation: Directly inspects filesystem attributes to confirm the target file is a physical, non-symbolic entity.
  5. Reserved Device Blocks: Prevents spoofing attempts using legacy system device designations (e.g., CON, PRN, AUX).
  6. Protected System Directory Fencing: Prevents configuration loading out of primary administrative operating system paths.
  7. 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.

Supply Chain and Trust

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.

The Servy Trust Boundary

Servy operates under a Single Trust Boundary security model. All services managed by Servy execute and persist runtime data within a shared root vault directory: %ProgramData%\Servy.

Architectural Design & Runtime Permissions

Because Servy.Service.exe executes directly under the identity of your configured service account, that account requires Modify permissions on the %ProgramData%\Servy directory tree to perform necessary runtime operations:

  • Database Operations: Writing service status updates to %ProgramData%\Servy\db\Servy.db requires POSIX/Win32 file locking permissions (-wal and -shm write-ahead logs) on the containing database directory.
  • Helper Extraction: Extracting runtime helper binaries (such as Servy.Restarter.exe) during lifecycle recovery routines.
  • Logging & Recovery: Writing logs to %ProgramData%\Servy\logs\Servy.Service.log and serializing process recovery metadata (%ProgramData%\Servy\recovery\).

Executable Permission Hardening (Mandatory)

While non-administrative runner accounts require Modify access at the directory level (%ProgramData%\Servy) to write log streams, database locks, and state files, restricting core binary executables and loaded assemblies to Read & Execute (RX) is mandatory for production security.

Running Set-ServyExePermissions.ps1 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, etc.) to execute arbitrary code under elevated administrative contexts.
  • DLL Hijacking: Blocks rogue or compromised non-admin identities from planting or replacing shared .dll dependencies 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 SYSTEM or Administrators.

You can enforce this hardening on core Servy binaries (Servy.Service.exe, Servy.Service.CLI.exe, and Servy.Restarter.exe or their .Net48.exe and *.dll counterparts) using the Set-ServyExePermissions.ps1 utility.

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.

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.

Script Availability

  • Servy v9.7+: Set-ServyExePermissions.ps1 is located directly in %ProgramFiles%\Servy after installation. For portable builds, it is included in the root of the portable package.
  • Versions prior to v9.7: Download the script directly from the repository:

Hardening Utility Usage

Run the script from an Elevated (Administrator) PowerShell session, specifying your service runner or target account:

# 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 executes a two-pass ACL update to safely convert directory-inherited permissions into explicit rules, purges previous Modify privileges for the specified account on the binaries, locks them down to Read & Execute, and preserves Full Control for NT AUTHORITY\SYSTEM and BUILTIN\Administrators using language-agnostic Well-Known SIDs.

What This Means for Your Deployment

  • Shared Trust Tier: All service accounts granted Modify access to %ProgramData%\Servy share the same security boundary. A custom service account can read the shared SQLite configuration database, inspect logs for other services, or interact with files in the vault.
  • Cross-Service Influence: Because Modify access is granted across the vault root, a compromised service account could alter shared database records, inspect files, or tamper with logs of co-located services. While running Set-ServyExePermissions.ps1 hardens core binary executables and DLLs in the vault against binary tampering, it does not isolate runtime database access or log files between co-located services.
  • Intended Use Environment: Servy is engineered for dedicated application servers, CI/CD runner environments, and workstations where all configured service accounts belong to a single, mutually trusted administrative tier.
  • Zero Trust Isolation: If your security architecture requires strict multi-tenant isolation (where Service A must be cryptographically and permission-isolated from Service B), services should be deployed across distinct Virtual Machines, isolated OS installations, or Windows Containers.

Automatic Permissions Table (v7.9+)

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 Modify User (Manual) Must be granted manually for services running under non-SYSTEM identities.
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; for elevated (admin) installs the account instead appears via the installer-added ACE.

Important

If you configure a service to run under a custom local or domain Service Account (or gMSA), you must manually grant that account Modify rights to %ProgramData%\Servy (and allow inheritance to subfolders). Without Modify rights, the service runner will fail to initialize database write locks, logs, or extract recovery helpers. Executable permissions must then be hardened independently on the .exe files using Set-ServyExePermissions.ps1. See Executable Permission Hardening (Mandatory) section for details.

File Locations and Recovery

Your master encryption keys are stored here:

  • Database: %ProgramData%\Servy\db\Servy.db
  • 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.

Critical Warning: Machine Migration

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:

  1. Export your services on the old machine. The export is unencrypted, so treat it like a physical key: Parameters, EnvironmentVariables, etc. may be written in plaintext.
  2. Move the export file to the new machine.
  3. Import the services. Because Servy never persists the LogOn account or password into the export, the imported services will run as LocalSystem by default.
  4. Re-enter the service account credentials manually in Servy Manager (or via servy-cli install) for any service that should not run as LocalSystem.

Step 4 is mandatory if your services run under a domain account, gMSA, or local account.

Best Practices

  • 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%\Servy folder to ensure no unauthorized users have been added manually.

Troubleshooting

  • Access Denied on Startup: This usually means the account running the service does not have permissions to the %ProgramData%\Servy folder. Refer to the Permissions Table above.
  • Decryption Error: This happens if the .dat files were moved from another computer or if the Windows MachineGuid was altered. You will need to re-enter every encrypted field - Password, Parameters, EnvironmentVariables, PreLaunchEnvironmentVariables, and the corresponding hook Parameters (PreLaunchParameters, PostLaunchParameters, PreStopParameters, PostStopParameters, FailureProgramParameters) - because all of them are stored under the same machine-bound AES key. If you have an Export from the original machine, import it now (per Critical Warning: Machine Migration) instead of reconfiguring each service by hand.

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.

Clone this wiki locally