# OpenVPN — CWE-407 Disclosure Brief
**2026-03-27 · Patch available — awaiting upstream merge**

## Finding

One multi-site defect in OpenVPN's TLS cipher negotiation and DCO (Data Channel Offload). `tls_item_in_cipher_list()` uses `strtok` for O(n×m) per-token scanning at 3 call sites during every TLS handshake. Patch ready for upstream review.

## The Defects

**openvpn-0001 (PATCHED — HIGH):** `ssl_ncp.c:272,388`; `dco.c:468`

```c
/* tls_item_in_cipher_list() — O(n×m) strtok scan per handshake at 3 sites: */
static bool
tls_item_in_cipher_list(const char *item, const char *list)
{
    char *tmp_list = strdup(list);
    char *token = strtok(tmp_list, ":");  /* O(n) tokens per call */
    while (token) {
        if (strcmp(token, item) == 0)    /* O(m) chars per compare */
            return true;
        token = strtok(NULL, ":");
    }
    /* Called at 3 sites per TLS handshake: O(3×n×m) total */
}
```

`tls_item_in_cipher_list()` re-splits and scans the cipher list string on every call. Called at 3 sites per TLS handshake: **O(3 × n × m) per handshake**. High multiplier at scale.

## Complexity Proof

For n ciphers in the list, m characters per cipher name:
- Per handshake: O(3×n×m) strtok scans
- Fixed: pre-split cipher array built at config load → O(1) per handshake check
- **High multiplier** — scales with cipher list length and TLS handshake rate.

## Impact

All OpenVPN deployments using negotiated cipher policy (NCP — Negotiable Crypto Parameters), which is enabled by default in OpenVPN 2.4+. This includes virtually all modern OpenVPN installations. `tls_item_in_cipher_list()` fires at 3 sites on every TLS handshake — client connect, renegotiation, and DCO setup. High-concurrency VPN gateways (enterprise VPN, cloud access brokers) with many simultaneous handshakes are most affected.

## The Fix

Pre-split the cipher list string into an array at configuration load time:

```c
/* Before */
/* Re-parse cipher list string on every call */
tls_item_in_cipher_list(cipher, options->tls_ciphersuites);

/* After */
/* CWE-407 fix: pre-split array built at config load for O(1) per-handshake check. */
/* Build once: */
cipher_list_arr = tls_split_cipher_list(options->tls_ciphersuites);

/* Check O(n) but without strdup/strtok overhead per call: */
for (int i = 0; cipher_list_arr[i]; i++) {
    if (strcmp(cipher_list_arr[i], cipher) == 0) return true;
}
```

## Patch

`defects/openvpn/patch/openvpn-0001-ssl-ncp-dco-cipher-array.patch`

## What We Ask

1. Confirm receipt and assign a GitHub Security Advisory or issue reference.
2. Validate the patch against your TLS negotiation and cipher list test suite.
3. Assess CVE eligibility — fires at 3 sites on every TLS handshake on high-concurrency gateways.
4. Coordinate a disclosure date — we are targeting 90 days from first contact.

Contact: see cover email. This brief is confidential until coordinated disclosure.
