Puru Kulkarni reported a bug in libcharon related to the handling of CREATE_CHILD_SA requests on unestablished IKE SAs that can result in the creation of a usable Child SA before authentication completes.
Creation of a Child SA Pre-Authentication
The IKEv2 implementation in the libcharon library doesn't reject CREATE_CHILD_SA requests on unestablished IKE SAs, which can allow an unauthenticated peer to potentially establish a usable Child SA. Affected are all strongSwan versions since 5.9.7.
CVE-2026-78135 has been assigned for this vulnerability.
Missing State Check Before Processing CREATE_CHILD_SA in libcharon
When a new IKE SA is created as responder, a bunch of tasks are queued in the passive queue of the task manager (libcharon's state machine). One of those tasks is child-create, which handles the creation of the first Child SA that's usually established during IKE_AUTH. The task is already queued because it e.g. grabs the nonces from the IKE_SA_INIT messages that are then used to derive the key material for the Child SA.
Incoming IKEv2 requests are handled in the task manager's process_request() function. And there is a check that rejects CREATE_CHILD_SA requests when the IKE SA is in the IKE_CREATED or IKE_CONNECTING state. The problem is that it only applies to new requests, i.e. while no passive exchanges are currently in progress.
This is how the code looks (simplified):
if (array_count(this->passive_tasks) == 0)
{ /* create tasks depending on request type, if not already some queued */
state = this->ike_sa->get_state(this->ike_sa);
switch (message->get_exchange_type(message))
{
...
case CREATE_CHILD_SA:
{
...
if (state == IKE_CREATED ||
state == IKE_CONNECTING)
{
DBG1(DBG_IKE, "received CREATE_CHILD_SA request for "
"unestablished IKE_SA, rejected");
return FAILED;
}
...
}
}
}
This check was added with 5.1.3 to fix an authentication bypass vulnerability on the initiator (CVE-2014-2338), which allowed a responder to establish an IKE SA pre-authentication by initiating a rekeying. On the initiator, no passive tasks are yet queued during IKE SA initiation, so the placement seemed appropriate. But it won't prevent a responder from processing a CREATE_CHILD_SA request during initiation while it already has several passive tasks queued.
When the initiator uses EAP for authentication, the authentication and creation of the first Child SA is deferred, leaving the tasks in the passive queue. If a CREATE_CHILD_SA request arrives at this time, the state check is never reached, and the request is processed as if the IKE_SA were established. The queued child-create task will process the request and attempt to establish a Child SA.
For the latter to work, the responder must either not configure an IP address pool, or specify an explicit remote traffic selector. Otherwise, traffic selector negotiation fails and no Child SA is created.
The half-open IKE SA and any installed IPsec SA are automatically removed after the default timeout of 30 seconds.
While versions before 5.9.7 also accept the CREATE_CHILD_SA requests prematurely, the authentication will fail and no Child SA is created due to an authentication failure. That's because before adding preliminary support for IKE_INTERMEDIATE exchanges with 5.9.7, the ike-auth task treated every exchange other than IKE_SA_INIT as IKE_AUTH and the processing would fail when the CREATE_CHILD_SA request is received as it can't contain the required payloads.
Remote code execution is not possible due to this issue.
As mentioned in the introduction, credit to Puru Kulkarni (puru1761) for finding this vulnerability and reporting it responsibly. It was independently reported by OpenAI.
Mitigation
Servers that don't accept EAP authentication are not vulnerable.
Common roadwarrior configurations that use EAP are also not vulnerable if they use a virtual IP address pool and remote_ts = dynamic (the default).
The just released strongSwan 6.1.0 fixes this vulnerability. For older releases, we provide a patch that fixes the vulnerability and should apply with appropriate hunk offsets.