🏠 Overview • 📦 Installation • 📖 Usage • 🏗️ Architecture • ❓ FAQ • ⚖️ SDKMAN! Comparison • 📜 Changelog • 🛡️ Security • 🤝 Contributing • 💬 Support
Currently, only versions 1.0.2 and newer of the Java Version Manager for Windows are supported with active security patches and vulnerability mitigations. Versions 1.0.0 and 1.0.1 are unsupported and deprecated due to missing defensive guardrails, elevation boundary mitigations, and parser protections introduced in 1.0.2.
| Version | Supported | Status |
|---|---|---|
>= 1.0.2 |
✅ | Supported (Active Security Maintenance) |
1.0.1 |
❌ | Unsupported (End of Life — Immediate Upgrade to 1.0.2+ Required) |
1.0.0 |
❌ | Unsupported (End of Life — Immediate Upgrade to 1.0.2+ Required) |
< 1.0.0 |
❌ | Unsupported (End of Life) |
DiamTek Java Version Manager (JVM) is engineered for enterprise developer workstations and managed corporate environments. The security perimeter is hardened against common Windows attack vectors, Local Privilege Escalation (LPE), and software supply chain tampering.
- Vulnerabilities Mitigated:
- TOCTOU Race Windows: Legacy automation utilities commonly write temporary elevation scripts (e.g.
%TEMP%\elevate.bator%TEMP%\admin.ps1) before executingStart-Process -Verb RunAs. This creates a critical Time-of-Check to Time-of-Use (TOCTOU) race window where an unprivileged local process can overwrite the temporary file before elevated execution, gainingNT AUTHORITY\SYSTEMor Administrator privileges. - Environment Variable Saturation / Spoofing: In Windows, an unprivileged user can register user-level environment variables (such as
[Environment]::SetEnvironmentVariable("SystemRoot", "C:\MaliciousDir", "User")). If a parent unprivileged process resolves$env:SystemRootor%SystemRoot%before callingStart-Process -Verb RunAs, an attacker can redirect the elevated executable path ($env:SystemRoot\System32\powershell.exe) or the elevated working directory (-WorkingDirectory "$env:SystemRoot\System32") to an attacker-controlled folder. This enables Search Order Hijacking, unauthorized DLL planting, and arbitrary code execution under elevated context.
- TOCTOU Race Windows: Legacy automation utilities commonly write temporary elevation scripts (e.g.
- Architectural Defense:
- JVM completely eliminates intermediate temporary elevation scripts. All administrative operations (such as system registry updates in legacy mode or system directory cleanups) are executed purely in-memory via Base64 UTF-16LE
-EncodedCommand. - System directory paths and elevation binaries are resolved strictly using the immutable Win32 SpecialFolder API (
[Environment]::GetFolderPath([Environment+SpecialFolder]::System)and[Environment+SpecialFolder]::Windows). These querySHGetKnownFolderPath(FOLDERID_System)and native Windows kernel APIs directly, completely ignoring the process environment block and immunizing elevation boundaries against environment variable saturation:
$bytes = [System.Text.Encoding]::Unicode.GetBytes($adminCommand) $encodedCommand = [Convert]::ToBase64String($bytes) $sys32Dir = [Environment]::GetFolderPath([Environment+SpecialFolder]::System) $systemPowerShell = Join-Path $sys32Dir "WindowsPowerShell\v1.0\powershell.exe" Start-Process -FilePath $systemPowerShell ` -Verb RunAs ` -WorkingDirectory $sys32Dir ` -ArgumentList "-NoProfile", "-NonInteractive", "-WindowStyle", "Hidden", "-EncodedCommand", $encodedCommand ` -Wait
- JVM completely eliminates intermediate temporary elevation scripts. All administrative operations (such as system registry updates in legacy mode or system directory cleanups) are executed purely in-memory via Base64 UTF-16LE
- EDR Compliance: This design prevents CrowdStrike, Microsoft Defender for Endpoint, and SentinelOne from triggering heuristic script-drop alerts in
%TEMP%and eliminates DLL planting vulnerabilities.
- Vulnerability Mitigated: Incomplete downloads, transit corruption, CDN cache poisoning, or malicious mirror swapping.
- Architectural Defense:
- Every remote JDK payload is cryptographically validated against vendor SHA256/SHA512 (and SHA1 for BellSoft Liberica) checksum endpoints using native .NET Cryptography APIs (
System.Security.Cryptography.SHA256/SHA512/SHA1). - Checksum validation is strictly decoupled from interactive prompts: passing
-y/--yesonly suppresses confirmation dialogs and will never bypass integrity verification. - Bypassing checksum validation requires an explicit, intentional
--skip-checksum(or--no-verify) flag for air-gapped or legacy mirrors without published hashes.
- Every remote JDK payload is cryptographically validated against vendor SHA256/SHA512 (and SHA1 for BellSoft Liberica) checksum endpoints using native .NET Cryptography APIs (
- Vulnerability Mitigated: Arbitrary shell command execution via untrusted project repository files (
.java-versionor.sdkmanrc). - Architectural Defense:
- Injected shell metacharacters (
&,|,<,>) embedded in version strings (e.g.,21 & calc.exe) are strictly filtered out by the parsing pipeline usingfindstr /v "[&|<>]". - Malicious lines are discarded before reaching the subshell execution boundary.
- Injected shell metacharacters (
- Vulnerability Mitigated: Legacy Windows
setx.exeimposes a hard 1,024-character buffer limit on thePATHenvironment variable. Runningsetxon a workstation with a longPATHsilently truncates the tail of the variable, corrupting system-wide software installations. - Architectural Defense: All global and machine environment updates leverage infinite-length .NET environment APIs (
[Environment]::SetEnvironmentVariable), completely bypassingsetx.exebuffer overrun vulnerabilities.
- Vulnerability Mitigated: Unauthorized binary replacement or build injection.
- Architectural Defense: Official release binaries (standalone MSIs, portable ZIPs) are built in isolated GitHub Actions runners and cryptographically signed using GitHub's OIDC Sigstore attestation authority (
actions/attest-build-provenance). - Verification Command:
gh attestation verify jvm-windows-1.0.1-x64.msi --owner DiamTek
- Vulnerability Mitigated: In-transit modification of self-updater payloads, malicious mirror spoofing, accidental or unauthorized rollbacks to older vulnerable versions, and script-locking denial-of-service.
- Architectural Defense:
[Stable]Channel: Pulls release artifacts and computes SHA-256 digests in-memory viaSystem.Security.Cryptography.SHA256, strictly matching against signed upstreamSHA256SUMS.txtmanifests before replacing local files. Any hash deviation immediately aborts execution and purges temporary files.[Nightly]Channel: Fetches the direct commit tip ofmain, parses semantic build stamps (JVM_BUILD), calculates the local SHA-256 fingerprint, and logs it in the audit trail.- Downgrade Safeguard: Both channels compare local
JVM_BUILDintegers against remote payloads. If a local workstation is running a build with an integer greater than the upstream target (local > remote), the updater halts execution ([ SKIP ] You are on a newer local build), preventing accidental regression. - Decoupled Ephemeral Runner: Executable replacement occurs via a detached runner script that polls for file handle release before atomic filesystem replacement, preventing partial write corruption.
- Vulnerability Mitigated: Arbitrary filesystem stream targeting, file disguise via NTFS Alternate Data Streams (
filename:stream), Win32 path canonicalization bypasses via trailing periods or whitespace, command-line parameter poisoning via shell metacharacters (^,&,|,<,>,;,",!,%), argument/flag injection (-), wildcard expansion attacks (*,?), and Windows device namespace lockups (CON,NUL,AUX,PRN,COM1-9,LPT1-9). - Architectural Defense:
- Implemented in
jvm.batunder:ValidateStrictIdentifier, enforcing an airtight multi-phase defensive pipeline:- Delayed Expansion Segregation: Validation begins under
setlocal disabledelayedexpansion. In Windowscmd.exe, evaluating untrusted strings containing exclamation marks (!) or percent signs (%) while delayed expansion is active can cause variable mutation or subshell command execution. The validator quarantines%_VSI_RAW%and uses parenthesized, quoted checks (echo("%_VSI_RAW%" | findstr "!"andfindstr "%%") to reject toxic inputs prior to enabling delayed expansion. - Win32 Canonicalization Bypass Prevention (
:VSI_StripTrailing): The Win32 subsystem automatically strips trailing dots (.) and spaces () during path normalization (e.g.,folder.orfolderresolves identically tofolder). Attackers exploit this behavior to bypass validation blacklists or trigger unexpected directory collisions.:VSI_StripTrailingiteratively strips trailing dots and spaces in a loop until the string is completely normalized. If stripping results in an empty value, execution immediately halts. - Alternate Data Stream (ADS) Colon Neutralization: On NTFS filesystems, colons separate filenames from Alternate Data Streams (e.g.,
file.txt:hidden.exe). Colon (:) characters are strictly forbidden and checked via batch substring substitution:if not "!_VSI_VAL!"=="!_VSI_VAL::=!" ( endlocal & endlocal set "JVM_EXIT_CODE=1" exit /b 1 )
- Path Traversal & Separator Quarantine: Slashes (
\,/) and relative directory traversals (..) are filtered using internal substring substitutions (!_VSI_VAL:\=!,!_VSI_VAL:/=!,!_VSI_VAL:..=!), completely preventing directory traversal escapes. - Leading Flag/Hyphen Neutralization: Identifiers beginning with a hyphen (
-) are immediately rejected (if "!_VSI_VAL:~0,1!"=="-"), neutralizing command-line flag injection into downstream sub-commands or native tools. - Internal Substitution Checks vs. Piped FINDSTR: Characters with syntactic meaning in
cmd.exe(^,&,|,<,>,;,") are tested through internal batch substitution (set "_VSI_SUB=!_VSI_VAL:&=!"etc.). Using batch substitution rather than piping tofindstrprevents poison metacharacters from escaping into subshells or pipeline boundaries during the check itself. - Wildcard and Reserved DOS Device Sanitization: Wildcards (
*,?) are detected using quoted regular-expression pattern matching (echo("!_VSI_VAL!" | findstr /R /C:"[*?]"). Additionally, legacy MS-DOS reserved device names (CON,PRN,AUX,NUL,COM1-COM9,LPT1-LPT9) are validated against a lookup loop to prevent Windows kernel file handle hangs. - Call-by-Name Variable Passing & Poison Token Immunity: In Windows batch scripts, passing raw values into subroutines (
call :sub "%VAR%") causescmd.exeto perform a second parsing pass over the command line. If%VAR%contains unescaped poison tokens (e.g.&,|,<,>), CMD splits the line and executes the tail as a separate command even inside double quotes. JVM passes variable names rather than variable values (call :ValidateStrictIdentifier VAR_NAME) and resolves them inside the subroutine using delayed expansion (!%1!), completely eliminating CMD double-parsing exploits. - Zero-Subshell Pure-Batch Character Loop (
:VSI_CharLoop): Identifier character validation executes entirely in pure batch using substring extraction in a loop, avoiding piping strings to external utilities (findstr) or spawning subshells where command injection could occur. - Quoted FINDSTR Isolation: Wherever
findstris invoked, piped input uses parenthesized echo syntax (echo("%_VSI_RAW%" | findstr ...) to avoid trailing whitespace contamination and delimiter collisions.
- Delayed Expansion Segregation: Validation begins under
- Implemented in
- Vulnerability Mitigated: Accidental or malicious destruction of host JDK directories during unlinking, uninstallation, or switching; recursive traversal into junction targets; and reparse point auto-recovery deadlocks caused by Win32
if existsemantics on dangling junctions. - Architectural Defense:
- Reparse Point Target Isolation (
Remove-DirectorySafely): Naive recursive folder deletion (such as standard PowerShellRemove-Item -Recurseor batch commands) can follow directory junctions and wipe the contents of the target installation folder (e.g., deleting the real JDK installation atC:\Program Files\Java\jdk-21when attempting to clean up%LOCALAPPDATA%\DiamTek\JVM\current).Remove-DirectorySafely(implemented inuninstall.ps1andbuild-msi.ps1) inspects directory attributes using($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint):- If the directory root is a reparse point, it is unbound immediately using
[System.IO.Directory]::Delete($path, $false)orcmd.exe /c "rmdir /q \"$path\"". The non-recursive unbind removes the junction pointer while leaving the target JDK directory contents 100% untouched. - Child reparse points within candidate stores are enumerated and safely unbound bottom-up prior to deleting parent directories.
- Tree deletion subsequently leverages
cmd.exe /c "rmdir /s /q \"$Path\""to guarantee junction safety in Windows PowerShell 5.1 without risking target deletion.
- If the directory root is a reparse point, it is unbound immediately using
- Broken Junction Auto-Recovery Without
if existDeadlock:- In Windows
cmd.exe, theif exist <path>operator evaluates whether the target directory of a directory junction exists, not whether the reparse point itself exists on disk. - If a user moves or deletes a JDK from disk, the junction pointing to it becomes "broken" or "dangling". A traditional script executing
if exist "%LINK%" rmdir "%LINK%"evaluates tofalse, skipping deletion. When the script subsequently executesmklink /J "%LINK%" "%NEW_TARGET%", Windows returns Win32 Error 183 (ERROR_ALREADY_EXISTS: Cannot create a file when that file already exists). - JVM completely eliminates this deadlock by unconditionally executing
rmdir "!CURRENT_SYMLINK!" >nul 2>&1without precedingif existchecks before every junction creation, ensuring instant, deterministic unbinding and self-healing.
- In Windows
- Reparse Point Target Isolation (
- Vulnerability Mitigated: Environment variable corruption through unintended type downgrades (converting dynamic
REG_EXPAND_SZvariables to staticREG_SZ), premature expansion of system variables (%SystemRoot%,%USERPROFILE%), buffer overflow truncation across user/machine boundaries, and terminal/installer deadlocks caused by unresponsive top-level desktop windows during environment broadcasts. - Architectural Defense:
- ValueKind Preservation (
REG_EXPAND_SZvsREG_SZ):- Reading registry values via standard high-level APIs often automatically expands nested environment strings, converting paths like
%SystemRoot%\System32intoC:\Windows\System32. Writing this expanded value back as a standardREG_SZpermanently breaks roaming profiles, variable relocations, and dynamic OS resolution. install.ps1,uninstall.ps1, andbuild-msi.ps1query registry keys directly using[Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment')with[Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames.- The engine determines the existing type via
$key.GetValueKind('Path'). It strictly preservesREG_EXPAND_SZ([Microsoft.Win32.RegistryValueKind]::ExpandString) whenever variable delimiters (%) are present or previously configured, preventing inadvertent type demotion toREG_SZ.
- Reading registry values via standard high-level APIs often automatically expands nested environment strings, converting paths like
- PATH Buffer & Truncation Safeguards:
- The engine computes combined PATH lengths (Machine PATH + User PATH) and enforces an 8,191-character hard ceiling (aborting modifications if exceeded to prevent environment block overflow) and a 2,048-character Win32 compatibility threshold with visual warnings.
- Non-Blocking Environment Broadcast (
SendMessageTimeout):- To notify the Windows shell, File Explorer, and active services of environment updates (
PATH,JAVA_HOME), scripts broadcast theWM_SETTINGCHANGE(0x001A) message toHWND_BROADCAST(0xFFFF) withlParam = "Environment". - Standard synchronous
SendMessagecalls block indefinitely if any running application has an unresponsive message pump (e.g., a hung tray utility or frozen GUI program). - JVM executes a native Win32 P/Invoke call to
SendMessageTimeoutwith flagsfuFlags = 2(SMTO_ABORTIFHUNG) and a timeout parameteruTimeout = 5000(5,000ms):[Win32.NativeMethods]::SendMessageTimeout( $HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, 'Environment', 2, # SMTO_ABORTIFHUNG (0x0002) 5000, # 5,000 ms timeout [ref]$result ) | Out-Null
- If any desktop window is hung, Windows immediately aborts waiting on that window and resumes broadcasting to the remaining windows, guaranteeing zero process hangs or installer freezeups.
- To notify the Windows shell, File Explorer, and active services of environment updates (
- ValueKind Preservation (
- Vulnerability Mitigated: Script crashes, permission denials, and installation failures on corporate enterprise endpoints enforced by AppLocker or Windows Defender Application Control (WDAC) running in PowerShell Constrained Language Mode (CLM); network download failures in enterprise proxy environments requiring integrated Windows authentication (NTLM/Kerberos).
- Architectural Defense:
- Constrained Language Mode (CLM) & WDAC Resiliency:
- Under PowerShell CLM, invoking custom .NET types, setting arbitrary static properties (such as
[System.Net.ServicePointManager]::SecurityProtocol), or compiling inline C# types viaAdd-Typeis restricted or triggers security exceptions (Cannot set property. Property setting is only supported on core types in this language mode). - The installer explicitly queries
$ExecutionContext.SessionState.LanguageModebefore executing advanced .NET operations ($isFullLanguage = ($ExecutionContext.SessionState.LanguageMode -eq 'FullLanguage')). When CLM is active (LanguageMode -ne 'FullLanguage'), the script selectively bypasses restricted .NET property mutations and relies on native, core cmdlets (Invoke-WebRequest,Invoke-RestMethod) that are fully allowed under WDAC policies.
- Under PowerShell CLM, invoking custom .NET types, setting arbitrary static properties (such as
- Enterprise Authenticated Proxy Support (
DefaultNetworkCredentials):- Corporate networks typically route outbound traffic through enterprise proxy firewalls requiring Integrated Windows Authentication (IWA). Unauthenticated requests fail with HTTP 407 (Proxy Authentication Required).
- When running in Full Language mode,
install.ps1binds system proxy credentials to native Kerberos/NTLM credentials:if ([System.Net.WebRequest]::DefaultWebProxy) { [System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials }
- On modern PowerShell (PS 6+ / 7+), it configures automatic corporate proxy delegation via default parameter values:
$PSDefaultParameterValues['Invoke-WebRequest:ProxyUseDefaultCredentials'] = $true $PSDefaultParameterValues['Invoke-RestMethod:ProxyUseDefaultCredentials'] = $true
- This allows seamless downloads from vendor endpoints (Adoptium, GitHub, Azul) across enterprise proxy gateways without credential prompts or plaintext credential storage.
- Constrained Language Mode (CLM) & WDAC Resiliency:
| Category | In-Scope | Out-of-Scope |
|---|---|---|
| Remote Code Execution | Unauthenticated RCE via auto-downloader, candidate engine, or archive unpacking | Code execution requiring an attacker to already control local administrator credentials |
| Path Traversal (Zip Slip) | Archive extraction writing files outside %LOCALAPPDATA%\DiamTek\JVM |
User explicitly running jvm link pointing to a compromised local directory |
| Privilege Escalation | Bypassing standard user boundaries to gain Administrator rights without UAC consent | Attacker already having elevated Administrator or SYSTEM privileges on the machine |
| Command Injection | Injecting commands via .java-version, .sdkmanrc, or CLI argument parsing |
Manually editing the jvm.bat file on local disk |
| Alternative Data Streams & Canonicalization | NTFS ADS stream injection (:stream) or trailing dot/space Win32 canonicalization bypasses in identifiers |
Modifying NTFS metadata with raw disk write privileges |
| Reparse Point & Junction Target Deletion | Recursive deletion traversing directory junctions to wipe host JDK installations | Manual deletion of target JDK folders by external tools or users |
| Environment & Registry Integrity | Accidental type demotion of REG_EXPAND_SZ to REG_SZ, or PATH overflow truncation |
Malicious software directly altering registry keys via background elevated service |
| Broadcast Deadlock & Hanging | Stalled process execution during WM_SETTINGCHANGE environment broadcasts |
Operating system kernel deadlock or failure of user32.dll subsystem |
| Transport Security | Silent acceptance of tampered/corrupted downloads when checksum is expected | Network denial-of-service or outages on vendor APIs (Adoptium, Oracle, GitHub, BellSoft) |
If you discover a potential security vulnerability in DiamTek Java Version Manager, please report it through coordinated disclosure. Do not create public GitHub issues or forum discussions for security vulnerabilities.
- GitHub Security Advisories (Preferred): Navigate to the repository's Private Vulnerability Reporting page to open a confidential report.
- Direct Email:
Send an encrypted or plaintext report to the project maintainer:
- Contact: Alexéy Shishkin
- Email: salexey09@gmail.com
- Discord (Direct Message): Reach out directly to @thehawk01 on Discord for initial coordination.
To help us triage and reproduce the issue rapidly, please include:
- The exact build number (
jvm versionorcmd.exe /c "jvm.bat --version"). - Target operating system and environment (e.g., Windows 11 23H2, standard user account vs. admin).
- Step-by-step reproduction instructions or a minimal Proof of Concept (PoC) payload.
- Assessment of the potential impact (e.g., LPE, arbitrary file write, shell injection).
We take all security reports with utmost urgency:
| Phase | Target SLA | Description |
|---|---|---|
| Initial Acknowledgment | < 48 hours | We confirm receipt of your report and begin preliminary assessment. |
| Triage & Reproduction | < 7 days | We validate the PoC in an isolated Windows sandbox and determine severity. |
| Patch & Release | < 30 days | We develop, verify via the automated test suite, and deploy a patched release. |
| Coordinated Disclosure | Negotiated | We publish security advisories and credit reporters (unless anonymity is requested). |