R. Elliott Childre reported a bug in libstrongswan when cloning certain identities that can lead to a double-free and potentially remote code execution.
Double-Free When Destroying Certain Cloned Identities
The clone() method of the identification_t class doesn't correctly handle identities that have an empty but non-NULL encoding. Both objects will point to the same location, resulting in a double-free once the second object is destroyed. This can lead to a crash and could potentially be exploitable for remote code execution. Affected are all strongSwan versions since 4.3.3.
CVE-2026-47895 has been assigned for this vulnerability.
Incorrect Check Before Cloning Identity Encoding
The identification_t class handles identities throughout the strongSwan project. Each object stores the identity's binary encoding as a chunk_t, which consists of a length and a pointer.
So the clone() method of that class contained the following code (simplified):
memcpy(clone, this, sizeof(private_identification_t));
if (this->encoded.len)
{
clone->encoded = chunk_clone(this->encoded);
}
First, the complete struct is copied, including the two sub-members of the encoded chunk. However, the latter is only updated after checking the length and not the pointer. Hence, if the chunk is empty but non-NULL, both encoded chunks point to the same location. This causes a double-free once the second object is destroyed.
Note that chunk_clone() returns chunk_empty ({ NULL, 0 }) for any chunk with length 0. So for most "empty" identities (e.g. "%any", "", or "@") this is not an issue as the encoding is chunk_empty to begin with or gets created with the chunk_clone(chunk_from_str()) construct with the same result.
Unfortunately, there is an exception. In order to configure identities with a specific binary encoding, the @# or <type>:# prefixes may be used so the rest of the string is parsed as hex-encoded value (see the docs on identity parsing for details). To do
so, the string is passed to chunk_from_hex().
This function has no shortcut for empty input. Instead, it always allocates a buffer, in this case with length 0, and returns that in a chunk. So if nothing follows the prefix, we end up with such an empty but non-NULL encoding. Technically, this depends on the malloc() implementation. Some might actually return NULL for a zero-length allocation, in which case this isn't an issue. But note that glibc is explicitly not one of them and always returns a unique pointer that can be passed to free().
The constructors that accept these prefixes are mostly used to parse identities in configs. However, they are also used to parse EAP identities/usernames as they have no explicit type assigned. The latter makes this exploitable for unauthenticated remote attackers. After completing an EAP-Identity exchange, the identity gets immediately cloned and stored in an auth_cfg_t object. This causes a double-free once the IKE SA is destroyed when the authentication failed, which is very likely because the parsed identity is empty.
Please be aware that many EAP methods exchange an identity/username internally, which uses the same constructors. So it might be possible to trigger this even when no EAP-Identity is explicitly requested from the client via eap_id setting. However, the identity is not cloned in all cases. Especially if the authentication fails, which, again, is likely. But it can depend on the configuration, the implementation and the protocol details. So to be safe, assume all EAP methods are vulnerable.
This applies similarly to XAuth with IKEv1, where the username is parsed the same way by the plugins. But it usually only gets cloned once the authentication succeeded. One notable exception is the xauth-eap plugin that passes the parsed username to an internally created EAP method that will immediately clone it.
The identification_create_from_data() constructor is also used to handle group membership via attribute certificates, but only after they'd been verified. It is also used to parse PPK IDs, however, they are only cloned after a PPK with matching owner is found, which is unlikely for an empty identity.
Remote code execution might be possible due to this issue.
As mentioned in the introduction, credit to R. Elliott Childre for finding and reporting this vulnerability.
Mitigation
Servers where strongSwan is linked to a malloc() implementation that returns NULL for zero-length allocations are not vulnerable.
Servers that don't use EAP or XAuth authentication are not vulnerable to remote attacks.
Servers that use EAP authentication but delegate it to a RADIUS server and don't request an EAP-Identity themselves are not vulnerable either. However, note that the eap-radius plugin parses Class and Filter-Id attributes as group identities if enabled, in which case a rogue RADIUS server is able to trigger the issue.
Servers that use IKEv1 with XAuth are not vulnerable unless they use the xauth-eap plugin.
The just released strongSwan 6.0.7 fixes this vulnerability. For older releases, we provide patches that fix the vulnerability and should apply with appropriate hunk offsets.