From b60a386a9c485b8295b5ea535f635af812f186b6 Mon Sep 17 00:00:00 2001 From: Griffin Francis Date: Wed, 12 Aug 2026 20:41:07 -0400 Subject: [PATCH] [mle] verify Response TLV against stored challenge before authoritative class (#13416) On a child, `HandleChildUpdateResponseOnChild()` accepted a Child Update Response carrying any Response TLV and classified the message as authoritative for key-sequence adoption, exempting it from the key-switch guard in `ProcessKeySequence()`. Verify a present Response TLV against the challenge actually sent to the parent before the authoritative classification, mirroring the parent-side verification in `HandleChildUpdateResponseOnParent()`. The stored challenge is also initialized in `Mle::Start()` as a safeguard so a Response TLV can never match an uninitialized value. Co-authored-by: aussinfosec --- src/core/thread/mle.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index baf0b1566..2231bf98b 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -201,6 +201,10 @@ Error Mle::Start(StartMode aMode) SetStateDetached(); + // Safeguard so a Response TLV can never match an uninitialized + // (predictable) challenge. + mPrevRoleRestorer.GenerateRandomChallenge(); + Get().AddUnicastAddress(mMeshLocalEid); Get().SubscribeMulticast(mLinkLocalAllThreadNodes); @@ -2411,6 +2415,11 @@ void Mle::HandleChildUpdateResponseOnChild(RxInfo &aRxInfo) case kRoleChild: VerifyOrExit((aRxInfo.mNeighbor == &mParent) && mParent.IsStateValid(), error = kErrorSecurity); + + if (!response.IsEmpty()) + { + VerifyOrExit(response == mPrevRoleRestorer.GetChallenge(), error = kErrorSecurity); + } break; default: