Import a profile into a desktop client and the first failure is often a line the client refuses to honour: a script hook it will not run, or a script-security value it considers too permissive. Raising the number makes the dialog go away. It also widens what that profile is allowed to execute on your machine, which is a strange thing to grant in order to dismiss a warning. Follow the import through to the directive and the decision becomes concrete.

From the import dialog to the directive

The profile is a text file with directives, and the client reads them before any tunnel exists. A directive such as up, down or tls-verify names an external program that OpenVPN should run at a defined moment. Whether OpenVPN is willing to run it is a separate setting called script-security, and the profile usually sets it too.

So the warning is not about cryptography or certificates. It is about a configuration file asking the client to execute something on the host, and the client checking whether its current permission level allows that request.

Two different failures look similar at this stage. A profile that asks for a level the client will not grant produces a refusal. A profile that asks for a level the client grants but the script is missing produces a failure at run time instead, and the two get conflated in support threads. One is a permission question and the other is a packaging question.

What each level actually opens

Level 0 forbids external program calls entirely, which is coherent for a client that configures its own interface without help and incoherent for one that shells out to the operating system. Level 1, the default, permits the built-in executables that interface and route configuration need. Neither level runs anything the user supplied.

LevelWhat OpenVPN may executeWhat it exposes
0No external programs at allInterface and route setup must not depend on helpers
1 (default)Built-in helpers such as ip, ifconfig, route or netshPrivileged commands the platform already ships
2Built-in helpers plus user-defined scriptsWhatever the named script does with the client's privileges
3Everything above, plus passwords in environment variablesCredentials visible to child processes and their logs

Level 2 is the interesting boundary, because it admits user-defined scripts. From that point the client's privileges apply to code you may never have read, invoked at moments you did not choose, with an environment that includes connection details. Level 3 goes further and allows passwords to be passed through environment variables, which is why the manual describes it as potentially unsafe.

None of these numbers is a strength setting. A profile at level 3 has no better encryption than one at level 1; it simply has a larger execution surface, and the tunnel is identical.

Decide what the profile deserves

Ask what the script is for before asking what level it needs. A hook that pushes DNS settings or repairs a route after connect is a legitimate reason to run something. A hook that calls an unfamiliar binary in a temporary directory is a reason to stop.

The script path matters as much as the script. A relative path resolves against whatever directory the client uses, and a writable directory turns a one-time import into a persistent execution slot. Absolute paths in a directory the user cannot modify are the shape to prefer.

Scripts also inherit the client's environment, which is where credentials and connection metadata live. That inheritance is exactly what makes level 3 dangerous in combination with a script that logs its environment, and it is the reason a diagnostic dump from a script-enabled client deserves a second look before it is pasted into a ticket. Strip the environment before sharing it.

grep -nE 'script-security|^up |^down |tls-verify' client.ovpn

Change one thing, then watch the teardown too

If the profile genuinely needs a script, change only the level and only for that profile. Run the client in the foreground with verbose output so the script's own errors are visible instead of being swallowed by a service manager.

openvpn --config client.ovpn --script-security 2 --verb 3
ip route show default

Test the whole lifecycle, not just the connect. A down hook that fails leaves routes pointing at a dead tunnel, which produces a machine that looks connected and cannot reach anything. Reconnect once and disconnect once before calling the change finished, and check the routing table after each.

Keep a copy of the original profile. If a platform client does not implement the same scripting model, deleting directives until the import succeeds can remove the DNS or route integration the tunnel needed, and the resulting connection will authenticate perfectly while resolving nothing.

The decision to record is narrow: which script, at which path, granted at which level, for which profile. Everything else in the profile is unchanged, and that is a sentence a reviewer can check.

Ũhoro ũhĩtĩte