Most people read an .ovpn file the way they read a router's settings page: addresses, routes, a cipher list. The part that executes code sits near the bottom, next to directives that look like plumbing, and it runs with whatever privilege the client already holds. That is the gap a careless or malicious profile exploits, and it is also the gap that turns a helpful DNS helper into a support problem three weeks later. The event directive, the security level and the file's ownership decide what can happen; the script's contents decide what actually does. Read all four before you connect.

A profile that runs a helper is a program, not a settings file

Directives such as route and dhcp-option describe state the client should establish, and the client treats them as data. An up script is different: the client spawns it as a process and hands it an environment full of connection details, so whatever its author wrote runs with your account's rights. On a laptop where the user is an administrator, that is a wide door for a file that arrived as an attachment or a paste from a forum thread. The distinction is not stylistic, it is the difference between configuration and code.

The myth worth retiring is that a profile can only reroute traffic. A helper that runs ip route add and one that runs curl against a remote host are the same mechanism, and the profile looks identical from the outside. Nothing in the file's appearance tells you which one you have, which is why the review has to reach the script itself.

What actually decides execution, and what the enabling lines look like

Three things gate a helper: the event directive that names it, the script-security level that permits it, and the client platform's own implementation. A profile can request a hook and still see nothing happen, because a mobile client or a stripped-down desktop build may not implement that event at all. Equally, a profile that asks for more permission than its function needs is telling you something about its origin. A permission level is a capability, not an approval. The enabling lines look like this, with a path that stands in for yours.

script-security 2
up /etc/openvpn/update-resolv-conf.sh
down /etc/openvpn/update-resolv-conf.sh

Level 0 refuses external programs and level 1, the default, permits only the client's built-in executables, so a hook needs 2 or higher; level 3 exists mainly for legacy password passing and is best avoided. A profile shipped with a hook needs both the directive and that level, which is why one line near the bottom of the file deserves the same scrutiny as the certificate block. The OpenVPN manual lists the permission levels, and its wording is worth reading next to whatever the profile actually asks for.

Ownership, path and what the helper is fed

A profile you trust that points at a script another account can rewrite is not a trusted arrangement, because the review you did yesterday no longer describes what runs today. Check the owner and mode of the helper, and check that the configured path resolves to the file you inspected rather than to a name something else can shadow. Arguments and environment deserve the same look: the client passes connection details to the hook, and a helper that logs its whole environment may be writing credentials into a support ticket. Prefer a documented integration from the operator or the platform over a DNS script copied from an unrelated post, since two resolver managers fighting over the same file produce a failure that looks like a broken VPN.

When you report a failing hook, redact the environment before pasting it anywhere. The dump that helps you debug can also carry the token that authenticates you.

Cleanup failures appear after the tunnel is gone

An up helper adds routes and resolver settings, and the down helper is supposed to take them away again. When the down hook is missing, fails silently, or never runs because the client was killed, the leftovers outlive the session. Traffic then takes a path nobody planned and names resolve through a resolver that should have been removed, while the tunnel itself looks healthy. Those symptoms arrive after the disconnect, which is why they get blamed on the network instead of on the profile.

Test teardown as a step of its own: bring the tunnel up, note the routes and the resolver, drop it, then confirm both are gone. A profile that connects cleanly can still leave state behind, and a zero exit code from the helper does not prove the resolver ended up pointing where you think.

Reviewing the helper and keeping an exit

Read the script end to end looking for three things: commands that need privilege, hardcoded paths that may not exist on your system, and any network call it makes. Then check how it fails, because a helper that swallows errors converts a configuration mistake into a mystery. If you cannot state in one sentence what the script does and who could change it, you are not ready to enable it. A profile that asks for more privilege than that sentence requires is the signal to stop.

Keep the last working profile and the helper it referenced in protected storage, with both versions noted, so a rollback is a copy rather than a reconstruction at the worst possible moment. If the helper exists only for a distribution or client version that no longer needs it, retire it in the configuration that owns the setting rather than raising privileges until the errors stop. That is the exit: fewer moving parts, not more permission.

Nsɛm a ɛfa ho