Skip to content

Environment Variables

Akram El Assas edited this page Jul 24, 2026 · 29 revisions

Table of Contents

  1. Introduction
  2. Environment Variable Expansion
  3. GUI
  4. CLI Option: --envVars
  5. CLI Example
  6. PowerShell Option: -EnvVars
  7. PowerShell Example
  8. Tips

Introduction

Servy allows you to define environment variables for the service process, enabling fine-grained control over the runtime context.

Environment variable expansion is supported in multiple areas of Servy configuration:

  • Service binary paths (--path / -Path)
  • Startup directories (--startupDir / -StartupDir)
  • Process parameters (--params / -Params)
  • Environment variables (--envVars / -EnvVars)

This makes it possible to reference existing system variables, user-defined variables, or paths dynamically in your configuration.

Environment Variable Expansion

Servy uses a sophisticated expansion engine that allows variables to reference each other. The resolution follows this specific order:

  1. System Environment: All current system and process environment variables are loaded first.
  2. Custom Overrides: Variables defined in the Environment Variables field (or --envVars) are added next. If a custom variable has the same name as a system variable, the custom value wins.
  3. Cross-Reference Expansion: Finally, all variables are scanned for %VAR% placeholders. These placeholders are resolved using the final merged set of variables.

Protected Variables

For security reasons Servy refuses to let --envVars / -EnvVars override a hard-coded list of variables that would otherwise enable privilege escalation or runtime injection (DLL/JIT profiler hijacking, debugger probes, search-path attacks, etc.). Any attempt to override one of these is silently ignored each time the service starts (during environment-variable expansion) and a warning is recorded in %ProgramData%\Servy\logs\Servy.Service.log:

Security: Blocked an attempt to override protected variable 'PATH'. Custom values for this variable are ignored to prevent privilege escalation.

The current list includes:

Category Environment Variables Security / Integrity Purpose
System Integrity PATH, COMSPEC, SYSTEMROOT, WINDIR, SYSTEMDRIVE, TEMP, TMP, PATHEXT, PROGRAMFILES, PROGRAMFILES(X86), PROGRAMW6432, COMMONPROGRAMFILES, COMMONPROGRAMFILES(X86), COMMONPROGRAMW6432 Protects core operating system paths, shell execution binaries, executable extension resolution rules, and system-wide temporary layout storage areas from redirection or manipulation.
Profile & Identity Redirection APPDATA, LOCALAPPDATA, PUBLIC, HOMEDRIVE, HOMEPATH, HOME, USERDOMAIN, USERDOMAIN_ROAMINGPROFILE, LOGONSERVER Prevents the malicious redirection of active user profile locations, local cache repositories, home path scopes, or domain network logons which could allow credential harvesting or state poisoning.
User & Profile Integrity USERNAME, USERPROFILE, ALLUSERSPROFILE, PROGRAMDATA, PSMODULEPATH Safeguards system configuration and initialization boundaries, tracking contexts, and default PowerShell utility module path discovery scopes from arbitrary interference.
.NET Runtime Injection & Diagnostics COR_ENABLE_PROFILING, COR_PROFILER, COR_PROFILER_PATH, CORECLR_ENABLE_PROFILING, CORECLR_PROFILER, CORECLR_PROFILER_PATH, DOTNET_STARTUP_HOOKS, DOTNET_ROOT, DOTNET_ROOT(x86), DOTNET_HOST_PATH, DOTNET_BUNDLE_EXTRACT_BASE_DIR, DOTNET_ADDITIONAL_DEPS, DOTNET_SHARED_STORE, DOTNET_DiagnosticPorts, COMPlus_DiagnosticPorts, DOTNET_EnableDiagnostics, COMPlus_EnableDiagnostics, DOTNET_EnableDiagnostics_IPC, COMPlus_EnableDiagnostics_IPC, DOTNET_EnableDiagnostics_Profiler, COMPlus_EnableDiagnostics_Profiler, DOTNET_EnableEventPipe, COMPlus_EnableEventPipe, DOTNET_GCName, COMPlus_GCName, DOTNET_GCPath, COMPlus_GCPath, DOTNET_LegacyHostPolicy, COMPlus_LegacyHostPolicy, DOTNET_LegacyTransform, COMPlus_LegacyTransform, DOTNET_PerfMapEnabled, COMPlus_PerfMapEnabled, DOTNET_ZapDisable, COMPlus_ZapDisable, DOTNET_DbgEnableMiniDump, COMPlus_DbgEnableMiniDump, DOTNET_DbgMiniDumpName, COMPlus_DbgMiniDumpName, DOTNET_DbgMiniDumpType, COMPlus_DbgMiniDumpType Shuts down execution hijacking and process attachment pathways targeting legacy, modern, and cross-compiled .NET/CoreCLR runtimes. This blocks unauthorized remote diagnostic socket endpoint exposure (DiagnosticPorts), runtime profiler/assembly DLL injection setups, custom Garbage Collector (GCPath) hijacking vectors, and the redirection of sensitive process memory dumps (DbgMiniDumpName) to insecure disk areas.
Java Injection JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JAVA_OPTS, JAVA_OPTIONS, CATALINA_OPTS, CATALINA_JAVA_OPTS, MAVEN_OPTS, M2_OPTS, GRADLE_OPTS, ANT_OPTS, JBOSS_JAVA_OPTS, WILDFLY_OPTS, CLASSPATH, JAVA_HOME, JRE_HOME, JDK_HOME Blocks execution exploits (such as malicious -javaagent arguments) loaded through native JVM diagnostics or shell-wrapper scripts commonly deployed in enterprise application frameworks like Tomcat, JBoss, Maven, and Gradle.
Node.js & NPM Injection NODE_OPTIONS, NODE_PATH, NODE_EXTRA_CA_CERTS, NPM_CONFIG_PREFIX, NPM_CONFIG_USERCONFIG, NPM_CONFIG_GLOBALCONFIG Defends Node.js runtime instances against preload option injections, local dependency resolution adjustments, rogue Certificate Authority additions (preventing Man-In-The-Middle traffic decryption), and npm registry config tampering.
Python Injection PYTHONSTARTUP, PYTHONPATH, PYTHONHOME, PYTHONIOENCODING, PYTHONFAULTHANDLER, PYTHONUSERBASE, PYTHONEXECUTABLE Prevents arbitrary script parsing or site-package source location hijacking through specialized system initialization hooks, site library layout directories, or custom interpreter path redirections.
Ruby & Perl Injection RUBYOPT, RUBYLIB, PERL5OPT, PERL5LIB Disallows option mapping switches and internal code inclusion path manipulations within local Ruby and Perl execution setups.
PHP Injection PHPRC, PHP_INI_SCAN_DIR Blocks attackers from supplying custom configuration directives or dynamically scanning arbitrary directories for malicious extension modules via modified initialization file search paths.
Global/Unix Fallback LD_PRELOAD, LD_LIBRARY_PATH Controls dynamic tracking or link-editor behaviors within Unix compatibility frameworks, MinGW subsystems, WSL boundaries, or Cygwin sandboxes to stop arbitrary binary instrumentation.
Windows AppCompat __COMPAT_LAYER, SHIM_FILE_LOG, SHIM_DEBUG_LEVEL, _NT_SYMBOL_PATH, _NT_ALT_SYMBOL_PATH, _NT_SOURCE_PATH, MICROSOFT_TELEMETRY_ENV_OVERRIDE Hardens execution trees against debugging diagnostics vectors, system symbol repository redirections, and application compatibility shim injection layer techniques.
PowerShell Hardening Bypass __PSLockDownPolicy, PSExecutionPolicyPreference Mitigates unauthorized administrative policy changes at process initialization by blocking programmatic overrides targeting Windows execution restrictions or the system LanguageMode.

If you need to extend PATH for the service process, modify the system PATH or use a custom variable name and reference it inside your application configuration.

Example of Expansion Logic

If your system has TEMP=C:\Windows\Temp and you define:

  • MY_ROOT=C:\ServyApp
  • MY_LOGS=%MY_ROOT%\logs
  • APP_TEMP=%TEMP%

The final environment seen by your process will be:

  • MY_ROOT: C:\ServyApp
  • MY_LOGS: C:\ServyApp\logs
  • APP_TEMP: C:\Windows\Temp

Note

Variable Ordering and Circular References: Variables are resolved using a multi-pass fixed-point algorithm, so the order in which you define them does not matter - MY_LOGS=%MY_ROOT%\logs resolves correctly even if MY_ROOT is defined later in the list. The expansion engine runs up to 5 passes; chains deeper than that will leave unresolved %VAR% placeholders and Servy logs a warning ("Environment variable expansion reached maximum pass limit").

Avoid circular references:

  • Self-reference (A=%A%): caught as soon as the expansion engine encounters a value that contains its own %NAME% token. Logged as Direct cycle detected for variable 'A'; leaving literal placeholder. and the placeholder is left literal (unless the OS already exports a value for A, in which case the inherited value is substituted to mimic Windows PATH-append semantics).
  • Multi-variable cycles (A=%B%, B=%A%, or longer chains like A=%B%, B=%C%, C=%A%): not detected by a dedicated check. The fixed-point loop is allowed up to 5 passes (AppConfig.MaxEnvVarExpansionPasses); if values are still changing when the limit is hit, the loop exits and Servy logs Environment variable expansion reached maximum pass limit. Indirect circular reference detected (e.g., A=%B%, B=%A%). Two-variable cycles typically degenerate into a self-reference inside the loop and so also surface as Direct cycle detected on a later pass.

GUI

The advanced tab in Servy allows setting environment variables for the service process:

servy-config-advanced-env

CLI Option: --envVars

The --envVars command-line option lets you specify environment variables for the service process.

  • Syntax: --envVars="VAR1=value1; VAR2=value2"
  • Separate multiple variables with semicolons (;) - Special characters can be escaped:
    • \= to escape =
    • \" to escape "
    • \; to escape ;
    • \\ to escape \
    • %% to escape % (collapses to a single %, matching cmd.exe behaviors) (starting from v8.5+)
  • Supports environment variable expansion. Example:
    --envVars="VAR1=%ProgramData%\MyApp; VAR2=%VAR1%\bin; CHANCE=100%%"
  • Useful for setting runtime context without changing system-wide environment variables.

CLI Example

servy-cli install `
  --name="MyNodeService" `
  --description="My NodeJS Server" `
  --path="%ProgramFiles%\nodejs\node.exe" `
  --startupDir="C:\Apps\App" `
  --params="C:\Apps\App\index.js" `
  --startupType="Automatic" `
  --envVars="NODE_ENV=production; APP_CONFIG=C:\Apps\App\config.json"

PowerShell Option: -EnvVars

The -EnvVars parameter lets you define environment variables when installing a service via PowerShell.

  • Type: string (semicolon-separated list, optional)
  • Apply the same escaping rules as the CLI.
  • Multiple variables are separated with semicolons (;)
  • Variables are applied only to the service process, not system-wide.

PowerShell Example

Import-Module "C:\Program Files\Servy\Servy.psm1" -Force

$installParams = @{
    Name         = "MyNodeService"
    Description  = "My NodeJS Server"
    Path         = "C:\Program Files\nodejs\node.exe"
    StartupDir   = "C:\Apps\App"
    Params       = "C:\Apps\App\index.js"
    StartupType  = "Automatic"

    EnvVars      = "NODE_ENV=production; APP_CONFIG=C:\Apps\App\config.json"
}

Install-ServyService @installParams

Tips

  • Case Insensitivity: Environment variable names are case-insensitive. Defining node_env will correctly override an existing NODE_ENV.
  • Expansion Order: You can reference both existing system variables (like %ProgramData%) and other custom variables defined in the same list.
  • Safe Percent Escaping: To pass a literal percent character into your environment safely and prevent it from being processed as an expansion block, use a double percent sign (%%). For example, defining ALERT_MSG=Battery at 100%% will expand correctly to Battery at 100% inside the service process.
  • Verification: To troubleshoot, if you aren't sure if your variables are applying correctly, run this to dump the environment to a file (PowerShell Admin):
servy-cli install --name="EnvTest" --path="C:\Windows\System32\cmd.exe" --params="/c set > C:\servy_env.txt && timeout /t 3600 /nobreak > nul" --envVars="MY_ROOT=C:\ServyApp; MY_LOGS=%MY_ROOT%\logs"
servy-cli restart --name="EnvTest"
Get-Content C:\servy_env.txt | Select-String "MY_LOGS"

Clone this wiki locally