diff --git a/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp b/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp
index 6ba164c83227b0..64b684712e4433 100644
--- a/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp
+++ b/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp
@@ -23,11 +23,15 @@
 #include <app/CommandHandler.h>
 #include <app/server/Server.h>
 #include <app/util/af.h>
+#include <setup_payload/SetupPayload.h>
 #include <support/CodeUtils.h>
 #include <support/logging/CHIPLogging.h>
 
 using namespace chip;
 
+// Specifications section 5.4.2.3. Announcement Duration
+constexpr uint32_t kMaxCommissionioningTimeoutSeconds = 15 * 60;
+
 bool emberAfAdministratorCommissioningClusterOpenCommissioningWindowCallback(chip::EndpointId endpoint,
                                                                              app::CommandHandler * commandObj,
                                                                              uint16_t commissioningTimeout, ByteSpan pakeVerifier,
@@ -36,10 +40,22 @@ bool emberAfAdministratorCommissioningClusterOpenCommissioningWindowCallback(chi
 {
     EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
     PASEVerifier verifier;
+    const uint8_t * verifierData = pakeVerifier.data();
+
     ChipLogProgress(Zcl, "Received command to open commissioning window");
+
     VerifyOrExit(!IsPairingWindowOpen(), status = EMBER_ZCL_STATUS_FAILURE);
     VerifyOrExit(sizeof(verifier) == pakeVerifier.size(), status = EMBER_ZCL_STATUS_FAILURE);
-    memcpy(&verifier[0][0], pakeVerifier.data(), pakeVerifier.size());
+    VerifyOrExit(iterations >= kPBKDFMinimumIterations, status = EMBER_ZCL_STATUS_FAILURE);
+    VerifyOrExit(iterations <= kPBKDFMaximumIterations, status = EMBER_ZCL_STATUS_FAILURE);
+    VerifyOrExit(salt.size() >= kPBKDFMinimumSaltLen, status = EMBER_ZCL_STATUS_FAILURE);
+    VerifyOrExit(salt.size() <= kPBKDFMaximumSaltLen, status = EMBER_ZCL_STATUS_FAILURE);
+    VerifyOrExit(commissioningTimeout <= kMaxCommissionioningTimeoutSeconds, status = EMBER_ZCL_STATUS_FAILURE);
+    VerifyOrExit(discriminator <= kMaxDiscriminatorValue, status = EMBER_ZCL_STATUS_FAILURE);
+
+    memcpy(&verifier[0][0], &verifierData[0], kSpake2p_WS_Length);
+    memcpy(&verifier[1][0], &verifierData[kSpake2p_WS_Length], kSpake2p_WS_Length);
+
     VerifyOrExit(OpenPairingWindowUsingVerifier(commissioningTimeout, discriminator, verifier, iterations, salt, passcodeID) ==
                      CHIP_NO_ERROR,
                  status = EMBER_ZCL_STATUS_FAILURE);
@@ -61,6 +77,7 @@ bool emberAfAdministratorCommissioningClusterOpenBasicCommissioningWindowCallbac
     EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
     ChipLogProgress(Zcl, "Received command to open basic commissioning window");
     VerifyOrExit(!IsPairingWindowOpen(), status = EMBER_ZCL_STATUS_FAILURE);
+    VerifyOrExit(commissioningTimeout <= kMaxCommissionioningTimeoutSeconds, status = EMBER_ZCL_STATUS_FAILURE);
     VerifyOrExit(OpenDefaultPairingWindow(ResetFabrics::kNo, commissioningTimeout) == CHIP_NO_ERROR,
                  status = EMBER_ZCL_STATUS_FAILURE);
     ChipLogProgress(Zcl, "Commissioning window is now open");
diff --git a/src/controller/CHIPDevice.cpp b/src/controller/CHIPDevice.cpp
index deeea808d10658..e7c410977dd065 100644
--- a/src/controller/CHIPDevice.cpp
+++ b/src/controller/CHIPDevice.cpp
@@ -370,11 +370,11 @@ CHIP_ERROR Device::OpenPairingWindow(uint16_t timeout, PairingWindowOption optio
         PASEVerifier verifier;
         ByteSpan salt(reinterpret_cast<const uint8_t *>(kSpake2pKeyExchangeSalt), strlen(kSpake2pKeyExchangeSalt));
         ReturnErrorOnFailure(
-            PASESession::GeneratePASEVerifier(verifier, kSpake2p_Iteration_Count, salt, randomSetupPIN, setupPayload.setUpPINCode));
+            PASESession::GeneratePASEVerifier(verifier, kPBKDFMinimumIterations, salt, randomSetupPIN, setupPayload.setUpPINCode));
 
         ReturnErrorOnFailure(
             cluster.OpenCommissioningWindow(successCallback, failureCallback, timeout, ByteSpan(&verifier[0][0], sizeof(verifier)),
-                                            setupPayload.discriminator, kSpake2p_Iteration_Count, salt, mPAKEVerifierID++));
+                                            setupPayload.discriminator, kPBKDFMinimumIterations, salt, mPAKEVerifierID++));
     }
     else
     {
diff --git a/src/protocols/secure_channel/PASESession.h b/src/protocols/secure_channel/PASESession.h
index 4cdfa798860603..08eecc75dde08b 100644
--- a/src/protocols/secure_channel/PASESession.h
+++ b/src/protocols/secure_channel/PASESession.h
@@ -53,6 +53,12 @@ extern const char * kSpake2pKeyExchangeSalt;
 constexpr uint16_t kPBKDFParamRandomNumberSize = 32;
 constexpr uint32_t kSpake2p_Iteration_Count    = 100;
 
+// Specifications section 3.9. Password-Based Key Derivation Function
+constexpr uint32_t kPBKDFMinimumIterations = 1000;
+constexpr uint32_t kPBKDFMaximumIterations = 100000;
+constexpr uint32_t kPBKDFMinimumSaltLen    = 16;
+constexpr uint32_t kPBKDFMaximumSaltLen    = 32;
+
 using namespace Crypto;
 
 constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8;