ovpn-dco 2.8.4: non-elevated OpenVPN GUI fails with CreateFile access denied (errno=5) on Windows 11 [Provided Workaround script]
@lstipakov is already working on this.
Since Aug 6, 2026.
- Dominant language
- C
- Stars
- 14.6k
- Forks
- 3.4k
- PR merge metrics
- No merged PRs in 30d
Description
This appears to be the same underlying problem reported in the previously closed issue, but it is still reproducible with OpenVPN 2.7.6 and ovpn-dco-win 2.8.4 on Windows 11.
Refered to the previus ticket https://github.com/OpenVPN/openvpn/issues/629
I was able to reproduce this issue and implement a working workaround.
Environment
- Windows 11 Pro 25H2 x64, OS Build 26200.8875
- OpenVPN Community 2.7.6
- OpenVPN GUI 11.65.0.0
- ovpn-dco-win 2.8.4
- OpenVPN GUI running as a standard, non-elevated user
OpenVPN reports the operating system internally as:
Windows version: 10.0.26200, amd64
This is still Windows 11; Windows 11 retains the NT version number 10.0 for compatibility.
Symptoms
The relevant error was:
Using device interface: ...\ovpn-dco
CreateFile failed on ovpn-dco device: ... Access is denied. (errno=5)
Failed to open ovpn-dco adapter
The same OpenVPN profile worked correctly when OpenVPN GUI was started with Run as administrator.
Adding:
disable-dco
also allowed OpenVPN GUI to connect as a standard user, but throughput was significantly lower.
This confirmed that the VPN profile, authentication, routing, server, and DCO driver itself were working. The failure occurred specifically when a non-elevated openvpn.exe process tried to open the ovpn-dco device interface.
Troubleshooting already attempted
The following actions did not solve the problem:
- uninstalling OpenVPN;
- deleting all ovpn-dco adapter instances;
- removing every ovpn-dco driver package from the Windows Driver Store;
- rebooting;
- reinstalling OpenVPN;
- reinstalling ovpn-dco-win 2.8.4;
- recreating the DCO adapter;
- resetting the Windows network stack;
- verifying that
OpenVPNServiceInteractivewas running; - verifying that the user was a member of the
OpenVPN Administratorsgroup.
After a complete uninstall, Driver Store cleanup, reboot, and clean reinstall, the newly created DCO device still returned:
Access is denied. (errno=5)
The failing operation remained the CreateFile() call against the ovpn-dco device path.
Root cause identified
The DCO driver was installed, loaded, and discoverable, but the effective per-device security descriptor did not allow the standard user's OpenVPN process to open the DCO device interface.
Reinstalling the driver did not correct that per-device ACL.
The workaround was to modify the security descriptor of the ovpn-dco Plug and Play device instance and grant access only to the current Windows user's SID.
What the workaround script does
The PowerShell script must be run once as administrator.
It performs the following operations:
-
Stops running
openvpn.exeandopenvpn-gui.exeprocesses. -
Checks whether a persistent DCO adapter exists by running:
tapctl.exe list --hwid ovpn-dco -
If the requested adapter does not exist, creates one with:
tapctl.exe create --hwid ovpn-dco --name "OpenVPN DCO User" -
Uses Windows SetupAPI to enumerate currently present devices in the Network device class:
{4d36e972-e325-11ce-bfc1-08002be10318} -
Selects only devices whose hardware ID is exactly:
ovpn-dco -
Reads the per-device security descriptor through:
SPDRP_SECURITY_SDSusing
SetupDiGetDeviceRegistryPropertyW(). -
Saves the original device instance IDs and SDDL security descriptors to a JSON backup under:
C:\ProgramData\OpenVPN\DcoAclFix -
Retrieves the SID of the current Windows user.
-
Adds the following access-control entry to the device DACL:
(A;;GRGWGX;;;<CURRENT_USER_SID>)This grants Generic Read, Generic Write, and Generic Execute access only to the current user.
-
Writes the updated security descriptor through:
SetupDiSetDeviceRegistryPropertyW(..., SPDRP_SECURITY_SDS, ...) -
Restarts each affected DCO device with:
pnputil.exe /restart-device <INSTANCE_ID> -
Optionally updates a specified
.ovpnprofile by:-
removing
disable-dco; -
removing existing
dev-nodedirectives; -
adding:
dev-node "OpenVPN DCO User"
-
The script does not grant device access to Everyone.
It does not modify the ACL of the ovpn-dco kernel service.
It modifies only the security descriptors of present Plug and Play devices whose hardware ID is exactly ovpn-dco.
How to locate and verify the OpenVPN profile
Before running the script with -ConfigPath, first identify the exact .ovpn profile used by the failing connection.
The profile filename is normally visible in the OpenVPN log, for example:
config = 'Client.ovpn'
It may also correspond to the connection name displayed by OpenVPN GUI.
Open PowerShell as Administrator and list the .ovpn profiles in the standard OpenVPN directories:
$OpenVpnRoots = @(
"$env:USERPROFILE\OpenVPN",
"$env:ProgramFiles\OpenVPN"
) | Where-Object {
Test-Path -LiteralPath $_
}
Get-ChildItem `
-Path $OpenVpnRoots `
-Filter "*.ovpn" `
-File `
-Recurse `
-ErrorAction SilentlyContinue |
Sort-Object FullName |
Select-Object FullName, LastWriteTime
Find the profile whose filename matches the profile shown in the OpenVPN log or OpenVPN GUI.
Set its exact path in a variable:
$ProfilePath = "C:\Path\To\Client.ovpn"
Verify that the file exists:
Test-Path -LiteralPath $ProfilePath
The result must be:
True
Review the relevant profile directives before making changes:
Get-Content -LiteralPath $ProfilePath |
Select-String -Pattern '^\s*(remote|dev|dev-node|disable-dco)\b'
Confirm that this is the correct VPN profile before continuing.
Create an additional manual backup:
$ManualBackup = "$ProfilePath.manual-backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
Copy-Item `
-LiteralPath $ProfilePath `
-Destination $ManualBackup
Write-Host "Manual profile backup: $ManualBackup"
The script also creates its own timestamped profile backup when -ConfigPath is used, but this manual backup provides an additional recovery copy.
How to run the workaround
Save or download the script as:
Fix-OpenVpnDcoAcl-English-Generic.ps1
For example, place it in the current user's Downloads directory.
Close OpenVPN GUI completely.
Open PowerShell as Administrator and define the script path:
$ScriptPath = "$env:USERPROFILE\Downloads\Fix-OpenVpnDcoAcl-English-Generic.ps1"
Verify that the script exists:
Test-Path -LiteralPath $ScriptPath
The result must be:
True
Allow scripts only for the current PowerShell process and unblock the downloaded file:
Set-ExecutionPolicy -Scope Process Bypass -Force
Unblock-File -LiteralPath $ScriptPath
Run the script and provide the previously verified OpenVPN profile:
& $ScriptPath -ConfigPath $ProfilePath
Administrator privileges are required only while applying the device ACL change.
When -ConfigPath is used, the script:
-
backs up the original device ACLs;
-
creates the persistent DCO adapter if necessary;
-
grants the current user's SID access to the DCO device;
-
restarts the affected device;
-
creates a timestamped backup of the
.ovpnfile; -
removes
disable-dco; -
removes existing
dev-nodedirectives; -
adds:
dev-node "OpenVPN DCO User"
An automatically created profile backup will have a name similar to:
Client.ovpn.bak-20260806-153000
After the script completes:
- Close the elevated PowerShell window.
- Start OpenVPN GUI normally.
- Do not use Run as administrator.
- Connect using the modified profile.
After applying this per-device ACL change, OpenVPN GUI was able to open the DCO device successfully as a standard user. DCO remained enabled and normal throughput was restored.
Running the ACL fix without modifying a profile
The script can also be run without -ConfigPath:
& $ScriptPath
In that mode, it changes the DCO device ACL but does not modify any .ovpn file.
The profile must then be edited manually:
-
Remove or comment out:
disable-dco -
Remove any existing
dev-nodedirective. -
Add:
dev-node "OpenVPN DCO User"
Using -ConfigPath is safer when the exact profile has already been identified and verified because the script creates a timestamped backup before modifying it.
ACL rollback
To restore the most recent DCO device ACL backup, close OpenVPN GUI, open PowerShell as Administrator, and run:
$ScriptPath = "$env:USERPROFILE\Downloads\Fix-OpenVpnDcoAcl-English-Generic.ps1"
Set-ExecutionPolicy -Scope Process Bypass -Force
Unblock-File -LiteralPath $ScriptPath
& $ScriptPath -Rollback
The script restores the original per-device SDDL values from the newest backup under:
C:\ProgramData\OpenVPN\DcoAclFix
It then restarts the affected DCO devices.
To see the available ACL backups:
Get-ChildItem `
-LiteralPath "C:\ProgramData\OpenVPN\DcoAclFix" `
-Filter "DcoAclBackup-*.json" |
Sort-Object LastWriteTime -Descending |
Select-Object FullName, LastWriteTime
To restore a specific ACL backup:
$AclBackup = "C:\ProgramData\OpenVPN\DcoAclFix\DcoAclBackup-YYYYMMDD-HHMMSS.json"
& $ScriptPath `
-Rollback `
-BackupFile $AclBackup
Restoring the original OpenVPN profile
The ACL rollback does not automatically restore a modified .ovpn profile.
List the profile backups created by the script:
$ProfileDirectory = Split-Path -Parent $ProfilePath
$ProfileFileName = Split-Path -Leaf $ProfilePath
Get-ChildItem `
-LiteralPath $ProfileDirectory `
-Filter "$ProfileFileName.bak-*" |
Sort-Object LastWriteTime -Descending |
Select-Object FullName, LastWriteTime
Select the backup that should be restored:
$ProfileBackup = "C:\Path\To\Client.ovpn.bak-YYYYMMDD-HHMMSS"
Restore it:
Copy-Item `
-LiteralPath $ProfileBackup `
-Destination $ProfilePath `
-Force
The separate manual backup created before running the script can also be restored in the same way.
After restoring the original profile, restart OpenVPN GUI normally.
Conclusion
This appears to show that, on affected systems, reinstalling OpenVPN or ovpn-dco-win does not address the actual failure.
The driver is installed, loaded, and discoverable, but the effective per-device security descriptor prevents the intended non-elevated OpenVPN process from opening the DCO device interface.
This script is a workaround, not an upstream fix.
The driver installer or device creation path should ensure that newly created ovpn-dco device instances receive a security descriptor compatible with OpenVPN GUI's intended non-elevated execution model. Access could potentially be granted to the appropriate OpenVPN local group or through another suitably restricted device ACL.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.