Adding --csd-wrapper to a profile hands a local script to a daemon that runs it during login, so the decision in front of you is a code review, not a preference toggle. The option exists so a gateway's host-check component can be replaced, and it takes a path to a script you supply. Everything below assumes the deployment owner has already said which posture check is required; if that part is still open, settle it first. The runbook has four moves: locate the failing stage, read the script, choose the identity it runs as, and prove the outcome.

Step 1: Locate the stage that failed

The client's final message is usually about a cookie, which is the end of a chain rather than the start of one. An HTTPS login, a server certificate check, an authentication exchange and a posture component all sit in front of that message.

Capture the version and the login address in use, then repeat the attempt with verbose output kept on your own terminal. Read the first error that is not a retry, not the last line of the transcript. If the log stops before any assessment component is named, the wrapper is not your problem yet. Adding it at that point only widens the surface you have to defend later.

openconnect --version
openconnect --verbose --user="$VPN_USER" vpn.example.com </dev/null

Keep the transcript local, because cookies and authentication responses are access material. A trace pasted into a chat thread is a credential leak even when the assessment step looks harmless. Share the error text and the point in the flow where it appeared, never the payload.

Step 2: Read the script before it enters a profile

A wrapper is only as trustworthy as the revision you reviewed, so pin that revision and store its hash beside the approval note. The two commands below give you a fingerprint and a cheap syntax check before you read a single line. They also give the next person a fixed reference, which matters when the file lives outside package management. Neither command tells you what the script does, so run them and keep reading.

sha256sum ./vpn-csd-wrapper.sh
bash -n ./vpn-csd-wrapper.sh

Read the whole file with four questions in mind: does it make outbound HTTP calls, does it read credential files or environment variables, does it write outside a temp directory, and does any branch report a passing posture without measuring anything. That last pattern is a policy bypass with a log line attached. Copied wrappers tend to smuggle it in behind a plausible-looking check. If the script decides the device is fine before it looks at the device, stop there.

Check for packed payloads as well, since a readable header proves nothing about the rest of the file. Downloading a script from a forum thread does not make it trustworthy just because its name echoes a real host-check component. Record who installed it, where it came from, and how it will be updated.

grep -nE 'base64 -d|xxd -r|eval |curl |wget ' ./vpn-csd-wrapper.sh

Step 3: Choose the identity the wrapper runs as

--csd-user drops privileges while the CSD, TNCC or HIP program executes. That account is part of the local execution arrangement, not the username submitted to the gateway.

Give the wrapper a dedicated account with no interactive shell, no sudo rights and no group memberships it does not need. Grant read access to the script and to the specific files it inspects, then test the drop before you touch the VPN profile. Finding the problem here is cheaper than finding it inside the client.

sudo -u vpn-csd /usr/local/libexec/vpn-csd-wrapper.sh

Dropping privileges limits the damage a bad script can do. It does not review the code, make the report truthful, or establish that the gateway administrator accepts this implementation as meeting device policy.

Step 4: Keep the change reversible

Back up the profile before editing it, and keep the wrapper in version control so a rollback restores a known hash rather than hunting for a copy. Write down the script path, hash, execution user and approver in one place.

To roll back, remove the option, restart the client and confirm the original error returns. If the gateway still rejects the login after rollback, something else changed as well, and finding that difference comes before retrying the wrapper. Keep the previous copy for the length of the change window, which for most teams means until the next maintenance slot has passed.

After a successful rollout, check two things rather than one: the tunnel comes up, and a device that should fail the posture check is still refused. A connection that works for everyone is not evidence that the assessment survived your change.

Shortcuts that create a second problem

Do not make the helper report a compliant state without running the required checks, and do not override the platform identity to match another operating system. Claiming a different platform is not evidence that the real device meets policy. It leaves you with a client that lies on every future login.

Disabling server verification, replaying a stale cookie and stacking unreviewed scripts all trade a visible failure for an invisible one. If the installed client cannot complete the supported flow, ask for an approved alternative instead of bending the one you have.

The OpenConnect manual documents --csd-wrapper and --csd-user separately, which is the hint that matters: the script and the identity are two decisions. Review them separately and write both down. Then the login prompt stops being a mystery you solve by pasting code.

Makomi ya ndenge moko