diff --git a/src/app/clusters/scenes-server/SceneHandlerImpl.cpp b/src/app/clusters/scenes-server/SceneHandlerImpl.cpp
index c29d1bbd5d27e8..4e01802f00f34a 100644
--- a/src/app/clusters/scenes-server/SceneHandlerImpl.cpp
+++ b/src/app/clusters/scenes-server/SceneHandlerImpl.cpp
@@ -16,10 +16,249 @@
  */
 
 #include <app/clusters/scenes-server/SceneHandlerImpl.h>
+#include <app/util/ember-io-storage.h>
+#include <app/util/endpoint-config-api.h>
+#include <app/util/odd-sized-integers.h>
 
 namespace chip {
 namespace scenes {
 
+namespace {
+
+template <int ByteSize, bool IsSigned>
+using OddSizedInteger        = app::OddSizedInteger<ByteSize, IsSigned>;
+using ConcreteAttributePath  = app::ConcreteAttributePath;
+using AttributeValuePairType = app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type;
+
+/// ConvertDefaultValueToWorkingValue
+/// @brief Helper function to convert a byte array to a value of the given type.
+/// @param EmberAfDefaultAttributeValue & defaultValue
+/// @return Value converted to the given working type
+template <typename Type>
+typename app::NumericAttributeTraits<Type>::WorkingType
+ConvertDefaultValueToWorkingValue(const EmberAfDefaultAttributeValue & defaultValue)
+{
+    if constexpr (sizeof(typename app::NumericAttributeTraits<Type>::WorkingType) <= 2)
+    {
+        return static_cast<typename app::NumericAttributeTraits<Type>::WorkingType>(defaultValue.defaultValue);
+    }
+
+    typename app::NumericAttributeTraits<Type>::StorageType sValue;
+    memcpy(&sValue, defaultValue.ptrToDefaultValue, sizeof(sValue));
+    return app::NumericAttributeTraits<Type>::StorageToWorking(sValue);
+}
+
+/// IsExactlyOneValuePopulated
+/// @brief Helper function to verify that exactly one value is populated in a given AttributeValuePairType
+/// @param AttributeValuePairType & type AttributeValuePairType to verify
+/// @return bool true if only one value is populated, false otherwise
+bool IsExactlyOneValuePopulated(const AttributeValuePairType & type)
+{
+    int count = 0;
+    if (type.valueUnsigned8.HasValue())
+        count++;
+    if (type.valueSigned8.HasValue())
+        count++;
+    if (type.valueUnsigned16.HasValue())
+        count++;
+    if (type.valueSigned16.HasValue())
+        count++;
+    if (type.valueUnsigned32.HasValue())
+        count++;
+    if (type.valueSigned32.HasValue())
+        count++;
+    if (type.valueUnsigned64.HasValue())
+        count++;
+    if (type.valueSigned64.HasValue())
+        count++;
+    return count == 1;
+}
+
+/// CapAttributeValue
+/// Cap the attribute value based on the attribute's min and max if they are defined,
+/// or based on the attribute's size if they are not.
+/// @param[in] aVPair   AttributeValuePairType
+/// @param[in] metadata  EmberAfAttributeMetadata
+///
+template <typename Type>
+void CapAttributeValue(typename app::NumericAttributeTraits<Type>::WorkingType & value, const EmberAfAttributeMetadata * metadata)
+{
+    using IntType     = app::NumericAttributeTraits<Type>;
+    using WorkingType = typename IntType::WorkingType;
+
+    WorkingType maxValue;
+    WorkingType minValue;
+    uint16_t bitWidth = static_cast<uint16_t>(emberAfAttributeSize(metadata) * 8);
+
+    // TODO Use min/max values from Type to obtain min/max instead of relying on metadata. See:
+    // https://github.com/project-chip/connectedhomeip/issues/35328
+
+    // Min/Max Value caps for the OddSize integers
+    if (metadata->IsSignedIntegerAttribute())
+    {
+        // We use emberAfAttributeSize for cases like INT24S, INT40S, INT48S, INT56S where numeric_limits<WorkingType>::max()
+        // wouldn't work
+        maxValue = static_cast<WorkingType>((1ULL << (bitWidth - 1)) - 1);
+        minValue = static_cast<WorkingType>(-(1ULL << (bitWidth - 1)));
+    }
+    else
+    {
+        // We use emberAfAttributeSize for cases like INT24U, INT40U, INT48U, INT56U where numeric_limits<WorkingType>::max()
+        // wouldn't work
+        if (ZCL_INT64U_ATTRIBUTE_TYPE == app::Compatibility::Internal::AttributeBaseType(metadata->attributeType))
+        {
+            maxValue = static_cast<WorkingType>(UINT64_MAX); // Bit shift of 64 is undefined so we use UINT64_MAX
+        }
+        else
+        {
+            maxValue = static_cast<WorkingType>((1ULL << bitWidth) - 1);
+        }
+        minValue = static_cast<WorkingType>(0);
+    }
+
+    // Ensure that the metadata's signedness matches the working type's signedness
+    VerifyOrDie(metadata->IsSignedIntegerAttribute() == std::is_signed<WorkingType>::value);
+
+    if (metadata->IsBoolean())
+    {
+        if (metadata->IsNullable() && (value != 1 && value != 0))
+        {
+            // If the attribute is nullable, the value can be set to NULL
+            app::NumericAttributeTraits<WorkingType>::SetNull(value);
+        }
+        else
+        {
+            // Caping the value to 1 in case values greater than 1 are set
+            value = value ? 1 : 0;
+        }
+        return;
+    }
+
+    // Check metadata for min and max values
+    if (metadata->HasMinMax())
+    {
+        const EmberAfAttributeMinMaxValue * minMaxValue = metadata->defaultValue.ptrToMinMaxValue;
+        minValue                                        = ConvertDefaultValueToWorkingValue<Type>(minMaxValue->minValue);
+        maxValue                                        = ConvertDefaultValueToWorkingValue<Type>(minMaxValue->maxValue);
+    }
+
+    // If the attribute is nullable, the min and max values calculated for types will not be valid, however this does not
+    // change the behavior here as the value will already be NULL if it is out of range. E.g. a nullable INT8U has a minValue of
+    // -127. The code above determin minValue = -128, so an input value of -128 would not enter the condition block below, but would
+    // be considered NULL nonetheless.
+    if (metadata->IsNullable() && (minValue > value || maxValue < value))
+    {
+        // If the attribute is nullable, the value can be set to NULL
+        app::NumericAttributeTraits<WorkingType>::SetNull(value);
+        return;
+    }
+
+    if (minValue > value)
+    {
+        value = minValue;
+    }
+    else if (maxValue < value)
+    {
+        value = maxValue;
+    }
+}
+
+/// @brief  Validate the attribute exists for a given cluster
+/// @param[in] endpoint   Endpoint ID
+/// @param[in] clusterID  Cluster ID
+/// @param[in] aVPair     AttributeValuePairType, will be mutated to cap the value if it is out of range
+/// @return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute) if the attribute does not exist for a given cluster or is not scenable
+/// @note This will allways fail for global list attributes. If we do want to make them scenable someday, we will need to
+///       use a different validation method.
+// TODO: Add check for "S" quality to determine if the attribute is scenable once suported :
+// https://github.com/project-chip/connectedhomeip/issues/24177
+CHIP_ERROR ValidateAttributePath(EndpointId endpoint, ClusterId cluster, AttributeValuePairType & aVPair)
+{
+    const EmberAfAttributeMetadata * metadata = emberAfLocateAttributeMetadata(endpoint, cluster, aVPair.attributeID);
+
+    if (nullptr == metadata)
+    {
+        return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
+    }
+
+    // There should never be more than one populated value in an ExtensionFieldSet
+    VerifyOrReturnError(IsExactlyOneValuePopulated(aVPair), CHIP_ERROR_INVALID_ARGUMENT);
+
+    switch (app::Compatibility::Internal::AttributeBaseType(metadata->attributeType))
+    {
+    case ZCL_BOOLEAN_ATTRIBUTE_TYPE:
+    case ZCL_INT8U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned8.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<uint8_t>(aVPair.valueUnsigned8.Value(), metadata);
+        break;
+    case ZCL_INT16U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned16.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<uint16_t>(aVPair.valueUnsigned16.Value(), metadata);
+        break;
+    case ZCL_INT24U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned32.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<3, false>>(aVPair.valueUnsigned32.Value(), metadata);
+        break;
+    case ZCL_INT32U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned32.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<uint32_t>(aVPair.valueUnsigned32.Value(), metadata);
+        break;
+    case ZCL_INT40U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<5, false>>(aVPair.valueUnsigned64.Value(), metadata);
+        break;
+    case ZCL_INT48U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<6, false>>(aVPair.valueUnsigned64.Value(), metadata);
+        break;
+    case ZCL_INT56U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<7, false>>(aVPair.valueUnsigned64.Value(), metadata);
+        break;
+    case ZCL_INT64U_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueUnsigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<uint64_t>(aVPair.valueUnsigned64.Value(), metadata);
+        break;
+    case ZCL_INT8S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned8.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<int8_t>(aVPair.valueSigned8.Value(), metadata);
+        break;
+    case ZCL_INT16S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned16.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<int16_t>(aVPair.valueSigned16.Value(), metadata);
+        break;
+    case ZCL_INT24S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned32.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<3, true>>(aVPair.valueSigned32.Value(), metadata);
+        break;
+    case ZCL_INT32S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned32.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<int32_t>(aVPair.valueSigned32.Value(), metadata);
+        break;
+    case ZCL_INT40S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<5, true>>(aVPair.valueSigned64.Value(), metadata);
+        break;
+    case ZCL_INT48S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<6, true>>(aVPair.valueSigned64.Value(), metadata);
+        break;
+    case ZCL_INT56S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<OddSizedInteger<7, true>>(aVPair.valueSigned64.Value(), metadata);
+        break;
+    case ZCL_INT64S_ATTRIBUTE_TYPE:
+        VerifyOrReturnError(aVPair.valueSigned64.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
+        CapAttributeValue<int64_t>(aVPair.valueSigned64.Value(), metadata);
+        break;
+    default:
+        return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
+    }
+
+    return CHIP_NO_ERROR;
+}
+} // namespace
+
 CHIP_ERROR
 DefaultSceneHandlerImpl::EncodeAttributeValueList(const List<AttributeValuePairType> & aVlist, MutableByteSpan & serializedBytes)
 {
@@ -58,7 +297,9 @@ DefaultSceneHandlerImpl::SerializeAdd(EndpointId endpoint, const ExtensionFieldS
     auto pair_iterator = extensionFieldSet.attributeValueList.begin();
     while (pair_iterator.Next())
     {
-        aVPairs[pairCount] = pair_iterator.GetValue();
+        AttributeValuePairType currentPair = pair_iterator.GetValue();
+        ReturnErrorOnFailure(ValidateAttributePath(endpoint, extensionFieldSet.clusterID, currentPair));
+        aVPairs[pairCount] = currentPair;
         pairCount++;
     }
     ReturnErrorOnFailure(pair_iterator.GetStatus());
diff --git a/src/app/clusters/scenes-server/scenes-server.cpp b/src/app/clusters/scenes-server/scenes-server.cpp
index acc2cd3a7dff80..ae10a3dd7ce11d 100644
--- a/src/app/clusters/scenes-server/scenes-server.cpp
+++ b/src/app/clusters/scenes-server/scenes-server.cpp
@@ -74,6 +74,11 @@ CHIP_ERROR AddResponseOnError(CommandHandlerInterface::HandlerContext & ctx, Res
         {
             resp.status = to_underlying(Protocols::InteractionModel::Status::ResourceExhausted);
         }
+        else if (CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute) == err)
+        {
+            // TODO: Confirm if we need to add UnsupportedAttribute status as a return for Scene Commands
+            resp.status = to_underlying(Protocols::InteractionModel::Status::InvalidCommand);
+        }
         else
         {
             resp.status = to_underlying(StatusIB(err).mStatus);
diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp
index ffb0a1fd5650ff..2e541cb0e76a95 100644
--- a/src/app/tests/TestSceneTable.cpp
+++ b/src/app/tests/TestSceneTable.cpp
@@ -17,7 +17,11 @@
  */
 
 #include <app/clusters/scenes-server/SceneTableImpl.h>
+#include <app/util/attribute-metadata.h>
 #include <app/util/mock/Constants.h>
+#include <app/util/mock/Functions.h>
+#include <app/util/mock/MockNodeConfig.h>
+#include <app/util/odd-sized-integers.h>
 #include <crypto/DefaultSessionKeystore.h>
 #include <lib/core/TLV.h>
 #include <lib/support/Span.h>
@@ -26,6 +30,8 @@
 #include <lib/core/StringBuilderAdapters.h>
 #include <pw_unit_test/framework.h>
 using namespace chip;
+using namespace chip::Test;
+using namespace chip::app::Clusters::Globals::Attributes;
 
 using SceneTable        = scenes::SceneTable<scenes::ExtensionFieldSetsImpl>;
 using SceneTableEntry   = scenes::DefaultSceneTableImpl::SceneTableEntry;
@@ -44,25 +50,29 @@ constexpr uint8_t defaultTestFabricCapacity = (defaultTestTableSize - 1) / 2;
 // Test Cluster ID
 constexpr chip::ClusterId kOnOffClusterId        = 0x0006;
 constexpr chip::ClusterId kLevelControlClusterId = 0x0008;
+constexpr chip::ClusterId kFakeClusterId         = 0x0007;
 constexpr chip::ClusterId kColorControlClusterId = 0x0300;
+constexpr chip::ClusterId kScenesClusterId       = 0x0062;
 
 // Test Endpoint ID
 constexpr chip::EndpointId kTestEndpoint1 = chip::Test::kMockEndpoint1;
 constexpr chip::EndpointId kTestEndpoint2 = chip::Test::kMockEndpoint2;
 constexpr chip::EndpointId kTestEndpoint3 = chip::Test::kMockEndpoint3;
+constexpr chip::EndpointId kTestEndpoint4 = kMockEndpointMin;
 
 // Test Attribute ID
-constexpr uint32_t kOnOffAttId               = 0x0000;
-constexpr uint32_t kCurrentLevelId           = 0x0000;
-constexpr uint32_t kCurrentFrequencyId       = 0x0004;
-constexpr uint32_t kCurrentSaturationId      = 0x0001;
-constexpr uint32_t kCurrentXId               = 0x0003;
-constexpr uint32_t kCurrentYId               = 0x0004;
-constexpr uint32_t kColorTemperatureMiredsId = 0x0007;
-constexpr uint32_t kEnhancedCurrentHueId     = 0x4000;
-constexpr uint32_t kColorLoopActiveId        = 0x4002;
-constexpr uint32_t kColorLoopDirectionId     = 0x4003;
-constexpr uint32_t kColorLoopTimeId          = 0x4004;
+constexpr uint32_t kOnOffAttId               = app::Clusters::OnOff::Attributes::OnOff::Id;
+constexpr uint32_t kCurrentLevelId           = app::Clusters::LevelControl::Attributes::CurrentLevel::Id;
+constexpr uint32_t kCurrentFrequencyId       = app::Clusters::LevelControl::Attributes::CurrentFrequency::Id;
+constexpr uint32_t kCurrentSaturationId      = app::Clusters::ColorControl::Attributes::CurrentSaturation::Id;
+constexpr uint32_t kCurrentXId               = app::Clusters::ColorControl::Attributes::CurrentX::Id;
+constexpr uint32_t kCurrentYId               = app::Clusters::ColorControl::Attributes::CurrentY::Id;
+constexpr uint32_t kColorTemperatureMiredsId = app::Clusters::ColorControl::Attributes::ColorTemperatureMireds::Id;
+constexpr uint32_t kEnhancedCurrentHueId     = app::Clusters::ColorControl::Attributes::EnhancedCurrentHue::Id;
+constexpr uint32_t kEnhancedColorMode        = app::Clusters::ColorControl::Attributes::EnhancedColorMode::Id;
+constexpr uint32_t kColorLoopActiveId        = app::Clusters::ColorControl::Attributes::ColorLoopActive::Id;
+constexpr uint32_t kColorLoopDirectionId     = app::Clusters::ColorControl::Attributes::ColorLoopDirection::Id;
+constexpr uint32_t kColorLoopTimeId          = app::Clusters::ColorControl::Attributes::ColorLoopTime::Id;
 
 // Test Group ID
 constexpr chip::GroupId kGroup1 = 0x101;
@@ -142,7 +152,7 @@ static app::Clusters::ScenesManagement::Structs::ExtensionFieldSet::Type CCexten
 
 static app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type OOPairs[1];
 static app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type LCPairs[2];
-static app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type CCPairs[8];
+static app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type CCPairs[9];
 
 static uint8_t OO_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 };
 static uint8_t LC_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 };
@@ -152,6 +162,222 @@ static uint32_t OO_buffer_serialized_length = 0;
 static uint32_t LC_buffer_serialized_length = 0;
 static uint32_t CC_buffer_serialized_length = 0;
 
+static const uint8_t defaultValueData64[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static EmberAfAttributeMinMaxValue minMaxValueBool = { false, false, true };
+static EmberAfAttributeMinMaxValue minMaxValue8  = { static_cast<uint8_t>(0), static_cast<uint8_t>(1), static_cast<uint8_t>(0xFE) };
+static EmberAfAttributeMinMaxValue minMaxValue8S = { static_cast<uint8_t>(0), static_cast<uint8_t>(-1),
+                                                     static_cast<uint8_t>(0x7F) };
+static EmberAfAttributeMinMaxValue minMaxValue16S = { static_cast<uint16_t>(0), static_cast<uint16_t>(-1),
+                                                      static_cast<uint16_t>(0x7FFD) };
+
+static EmberAfAttributeMetadata mockMetadataBool = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(&minMaxValueBool),
+    .attributeId   = 0,
+    .size          = 1,
+    .attributeType = ZCL_BOOLEAN_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint8 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(static_cast<uint8_t>(0)),
+    .attributeId   = 0,
+    .size          = 1,
+    .attributeType = ZCL_INT8U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE | ATTRIBUTE_MASK_NULLABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint8Max = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(&minMaxValue8),
+    .attributeId   = 0,
+    .size          = 1,
+    .attributeType = ZCL_INT8U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE | ATTRIBUTE_MASK_NULLABLE | ATTRIBUTE_MASK_MIN_MAX,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint16 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(static_cast<uint32_t>(0)),
+    .attributeId   = 0,
+    .size          = 2,
+    .attributeType = ZCL_INT16U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint24 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(static_cast<uint32_t>(0)),
+    .attributeId   = 0,
+    .size          = 3,
+    .attributeType = ZCL_INT24U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint32 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(static_cast<uint32_t>(0)),
+    .attributeId   = 0,
+    .size          = 4,
+    .attributeType = ZCL_INT32U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint40 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 5,
+    .attributeType = ZCL_INT40U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint48 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 6,
+    .attributeType = ZCL_INT48U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint56 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 7,
+    .attributeType = ZCL_INT56U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataUint64 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 8,
+    .attributeType = ZCL_INT64U_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt8 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(&minMaxValue8S),
+    .attributeId   = 0,
+    .size          = 1,
+    .attributeType = ZCL_INT8S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE | ATTRIBUTE_MASK_MIN_MAX,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt16 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(&minMaxValue16S),
+    .attributeId   = 0,
+    .size          = 2,
+    .attributeType = ZCL_INT16S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE | ATTRIBUTE_MASK_MIN_MAX,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt24 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(static_cast<uint32_t>(0)),
+    .attributeId   = 0,
+    .size          = 3,
+    .attributeType = ZCL_INT24S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt32 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(static_cast<uint32_t>(0)),
+    .attributeId   = 0,
+    .size          = 4,
+    .attributeType = ZCL_INT32S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt40 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 5,
+    .attributeType = ZCL_INT40S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt48 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 6,
+    .attributeType = ZCL_INT48S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt56 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 7,
+    .attributeType = ZCL_INT56S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+static EmberAfAttributeMetadata mockMetadataInt64 = {
+    .defaultValue  = EmberAfDefaultOrMinMaxAttributeValue(defaultValueData64),
+    .attributeId   = 0,
+    .size          = 8,
+    .attributeType = ZCL_INT64S_ATTRIBUTE_TYPE,
+    .mask          = ATTRIBUTE_MASK_WRITABLE,
+};
+
+// clang-format off
+static const MockNodeConfig SceneMockNodeConfig({
+    MockEndpointConfig(kTestEndpoint1, {
+        MockClusterConfig(kScenesClusterId, {}),
+        MockClusterConfig(kOnOffClusterId, {
+            MockAttributeConfig(kOnOffAttId, mockMetadataBool)
+        }),
+        MockClusterConfig(kLevelControlClusterId, {
+            MockAttributeConfig(kCurrentLevelId, mockMetadataUint8Max), MockAttributeConfig(kCurrentFrequencyId, mockMetadataUint16)
+        }),
+    }),
+    MockEndpointConfig(kTestEndpoint2, {
+        MockClusterConfig(kScenesClusterId, {}),
+        MockClusterConfig(kOnOffClusterId, {
+            MockAttributeConfig(kOnOffAttId, mockMetadataBool)
+        }),
+        MockClusterConfig(kColorControlClusterId, {
+            MockAttributeConfig(kCurrentSaturationId, mockMetadataUint8), MockAttributeConfig(kCurrentXId, mockMetadataUint16),
+            MockAttributeConfig(kCurrentYId, mockMetadataUint16), MockAttributeConfig(kColorTemperatureMiredsId, mockMetadataUint16),
+            MockAttributeConfig(kEnhancedCurrentHueId, mockMetadataUint16), MockAttributeConfig(kEnhancedColorMode, mockMetadataUint8),
+            MockAttributeConfig(kColorLoopActiveId, mockMetadataUint8), MockAttributeConfig(kColorLoopDirectionId, mockMetadataUint8),
+            MockAttributeConfig(kColorLoopTimeId, mockMetadataUint16)
+        }),
+    }),
+    MockEndpointConfig(kTestEndpoint3, {
+        MockClusterConfig(kScenesClusterId, {}),
+        MockClusterConfig(kOnOffClusterId, {
+            MockAttributeConfig(kOnOffAttId, mockMetadataBool)
+        }),
+        MockClusterConfig(kLevelControlClusterId, {
+            MockAttributeConfig(kCurrentLevelId, mockMetadataUint8Max), MockAttributeConfig(kCurrentFrequencyId, mockMetadataUint16)
+        }),
+        MockClusterConfig(kColorControlClusterId, {
+            MockAttributeConfig(kCurrentSaturationId, mockMetadataUint8), MockAttributeConfig(kCurrentXId, mockMetadataUint16),
+            MockAttributeConfig(kCurrentYId, mockMetadataUint16), MockAttributeConfig(kColorTemperatureMiredsId, mockMetadataUint16),
+            MockAttributeConfig(kEnhancedCurrentHueId, mockMetadataUint16), MockAttributeConfig(kEnhancedColorMode, mockMetadataUint8),
+            MockAttributeConfig(kColorLoopActiveId, mockMetadataUint8), MockAttributeConfig(kColorLoopDirectionId, mockMetadataUint8),
+            MockAttributeConfig(kColorLoopTimeId, mockMetadataUint8)
+        }),
+    }),
+
+    MockEndpointConfig(kTestEndpoint4, {
+        MockClusterConfig(kScenesClusterId, {}),
+        MockClusterConfig(MockClusterId(kColorControlClusterId), {
+            MockAttributeConfig(MockAttributeId(kCurrentSaturationId), mockMetadataUint24), MockAttributeConfig(MockAttributeId(kCurrentXId), mockMetadataUint32),
+            MockAttributeConfig(MockAttributeId(kCurrentYId), mockMetadataUint48), MockAttributeConfig(MockAttributeId(kColorTemperatureMiredsId), mockMetadataUint56),
+            MockAttributeConfig(MockAttributeId(kEnhancedCurrentHueId), mockMetadataUint64), MockAttributeConfig(MockAttributeId(kEnhancedColorMode), mockMetadataInt8),
+            MockAttributeConfig(MockAttributeId(kColorLoopActiveId), mockMetadataInt16), MockAttributeConfig(MockAttributeId(kColorLoopDirectionId), mockMetadataInt24),
+            MockAttributeConfig(MockAttributeId(kColorLoopTimeId), mockMetadataInt32)
+        }),
+        MockClusterConfig(MockClusterId(kOnOffClusterId), {
+            MockAttributeConfig(MockAttributeId(kOnOffAttId), mockMetadataInt48)
+        }),
+        MockClusterConfig(MockClusterId(kLevelControlClusterId), {
+            MockAttributeConfig(MockAttributeId(kCurrentLevelId), mockMetadataInt56), MockAttributeConfig(MockAttributeId(kCurrentFrequencyId), mockMetadataInt64)
+        }),
+        MockClusterConfig(MockClusterId(kFakeClusterId), {
+            MockAttributeConfig(MockAttributeId(kCurrentLevelId), mockMetadataUint40), MockAttributeConfig(MockAttributeId(kCurrentFrequencyId), mockMetadataInt40)
+        }),
+    }),
+});
+// clang-format on
+
 /// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control
 class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
 {
@@ -191,6 +417,16 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
                 clusterBuffer.reduce_size(3);
             }
         }
+        else if (endpoint == kTestEndpoint4)
+        {
+            if (clusterBuffer.size() >= 3)
+            {
+                buffer[0] = MockClusterId(kOnOffClusterId);
+                buffer[1] = MockClusterId(kLevelControlClusterId);
+                buffer[2] = MockClusterId(kColorControlClusterId);
+                clusterBuffer.reduce_size(3);
+            }
+        }
         else
         {
             clusterBuffer.reduce_size(0);
@@ -208,7 +444,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
             }
         }
 
-        if (endpoint == kTestEndpoint1)
+        if (endpoint == kTestEndpoint2)
         {
             if (cluster == kOnOffClusterId || cluster == kColorControlClusterId)
             {
@@ -216,7 +452,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
             }
         }
 
-        if (endpoint == kTestEndpoint1)
+        if (endpoint == kTestEndpoint3)
         {
             if (cluster == kOnOffClusterId || cluster == kLevelControlClusterId || cluster == kColorControlClusterId)
             {
@@ -224,6 +460,15 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
             }
         }
 
+        if (endpoint == kTestEndpoint4)
+        {
+            if (cluster == MockClusterId(kColorControlClusterId) || cluster == MockClusterId(kLevelControlClusterId) ||
+                cluster == MockClusterId(kColorControlClusterId) || cluster == MockClusterId(kFakeClusterId))
+            {
+                return true;
+            }
+        }
+
         return false;
     }
 
@@ -258,7 +503,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
                 break;
             }
         }
-        if (endpoint == kTestEndpoint1)
+        if (endpoint == kTestEndpoint2)
         {
             switch (cluster)
             {
@@ -280,7 +525,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
                 break;
             }
         }
-        if (endpoint == kTestEndpoint1)
+        if (endpoint == kTestEndpoint3)
         {
             switch (cluster)
             {
@@ -347,7 +592,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
         }
 
         // Takes values from cluster in Endpoint 2
-        if (endpoint == kTestEndpoint1)
+        if (endpoint == kTestEndpoint2)
         {
             switch (cluster)
             {
@@ -369,7 +614,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl
         }
 
         // Takes values from cluster in Endpoint 3
-        if (endpoint == kTestEndpoint1)
+        if (endpoint == kTestEndpoint3)
         {
             switch (cluster)
             {
@@ -440,6 +685,7 @@ class TestSceneTable : public ::testing::Test
         SceneTable * sceneTable = scenes::GetSceneTableImpl();
         ASSERT_NE(sceneTable, nullptr);
         ASSERT_EQ(sceneTable->Init(mpTestStorage), CHIP_NO_ERROR);
+        SetMockNodeConfig(SceneMockNodeConfig);
     }
 
     static void TearDownTestSuite()
@@ -531,34 +777,32 @@ TEST_F(TestSceneTable, TestHandlerFunctions)
     TLV::TLVReader reader;
     TLV::TLVWriter writer;
 
-    static const uint8_t OO_av_payload     = 0x01;
-    static const uint16_t LC_av_payload[2] = { 0x64, 0x01F0 };
-    static const uint16_t CC_av_payload[8] = { 0 };
-
     OOPairs[0].attributeID = kOnOffAttId;
-    OOPairs[0].valueUnsigned8.SetValue(OO_av_payload);
+    OOPairs[0].valueUnsigned8.SetValue(0x01);
 
     LCPairs[0].attributeID = kCurrentLevelId;
-    LCPairs[0].valueUnsigned8.SetValue(static_cast<uint8_t>(LC_av_payload[0]));
+    LCPairs[0].valueUnsigned8.SetValue(0x64);
     LCPairs[1].attributeID = kCurrentFrequencyId;
-    LCPairs[1].valueUnsigned16.SetValue(LC_av_payload[1]);
+    LCPairs[1].valueUnsigned16.SetValue(0x01F0);
 
     CCPairs[0].attributeID = kCurrentSaturationId;
-    CCPairs[0].valueUnsigned8.SetValue(static_cast<uint8_t>(CC_av_payload[0]));
+    CCPairs[0].valueUnsigned8.SetValue(0);
     CCPairs[1].attributeID = kCurrentXId;
-    CCPairs[1].valueUnsigned16.SetValue(CC_av_payload[1]);
+    CCPairs[1].valueUnsigned16.SetValue(0);
     CCPairs[2].attributeID = kCurrentYId;
-    CCPairs[2].valueUnsigned16.SetValue(CC_av_payload[2]);
+    CCPairs[2].valueUnsigned16.SetValue(0);
     CCPairs[3].attributeID = kColorTemperatureMiredsId;
-    CCPairs[3].valueUnsigned16.SetValue(CC_av_payload[3]);
+    CCPairs[3].valueUnsigned16.SetValue(0);
     CCPairs[4].attributeID = kEnhancedCurrentHueId;
-    CCPairs[4].valueUnsigned16.SetValue(CC_av_payload[4]);
-    CCPairs[5].attributeID = kColorLoopActiveId;
-    CCPairs[5].valueUnsigned8.SetValue(static_cast<uint8_t>(CC_av_payload[5]));
-    CCPairs[6].attributeID = kColorLoopDirectionId;
-    CCPairs[6].valueUnsigned8.SetValue(static_cast<uint8_t>(CC_av_payload[6]));
-    CCPairs[7].attributeID = kColorLoopTimeId;
-    CCPairs[7].valueUnsigned8.SetValue(static_cast<uint8_t>(CC_av_payload[7]));
+    CCPairs[4].valueUnsigned16.SetValue(0);
+    CCPairs[5].attributeID = kEnhancedColorMode;
+    CCPairs[5].valueUnsigned8.SetValue(0);
+    CCPairs[6].attributeID = kColorLoopActiveId;
+    CCPairs[6].valueUnsigned8.SetValue(0);
+    CCPairs[7].attributeID = kColorLoopDirectionId;
+    CCPairs[7].valueUnsigned8.SetValue(0);
+    CCPairs[8].attributeID = kColorLoopTimeId;
+    CCPairs[8].valueUnsigned16.SetValue(0);
 
     // Initialize Extension Field sets as if they were received by add commands
     OOextensionFieldSet.clusterID          = kOnOffClusterId;
@@ -572,7 +816,8 @@ TEST_F(TestSceneTable, TestHandlerFunctions)
     ByteSpan LC_list(LC_buffer);
     ByteSpan CC_list(CC_buffer);
 
-    uint8_t buffer[scenes::kMaxFieldBytesPerCluster] = { 0 };
+    constexpr uint16_t bufferSize = 1024;
+    uint8_t buffer[bufferSize]    = { 0 };
     MutableByteSpan buff_span(buffer);
 
     // Serialize Extension Field sets as if they were recovered from memory
@@ -626,11 +871,11 @@ TEST_F(TestSceneTable, TestHandlerFunctions)
     EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
     EXPECT_EQ(CHIP_NO_ERROR, extensionFieldSetIn.attributeValueList.Decode(reader));
 
-    EXPECT_TRUE(mpSceneHandler->SupportsCluster(kTestEndpoint1, extensionFieldSetIn.clusterID));
-    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint1, extensionFieldSetIn, buff_span));
+    EXPECT_TRUE(mpSceneHandler->SupportsCluster(kTestEndpoint2, extensionFieldSetIn.clusterID));
+    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint2, extensionFieldSetIn, buff_span));
 
     // Verify the handler extracted buffer matches the initial field sets
-    EXPECT_EQ(0, memcmp(CC_list.data(), buff_span.data(), buff_span.size()));
+    EXPECT_EQ(0, memcmp(CC_list.data(), buff_span.data(), CC_list.size()));
     memset(buffer, 0, buff_span.size());
     buff_span = MutableByteSpan(buffer);
 
@@ -641,7 +886,7 @@ TEST_F(TestSceneTable, TestHandlerFunctions)
     // Verify Encoding the Extension field set returns the same data as the one serialized for on off previously
     writer.Init(buff_span);
     EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), extensionFieldSetOut.attributeValueList));
-    EXPECT_EQ(0, memcmp(OO_list.data(), buff_span.data(), buff_span.size()));
+    EXPECT_EQ(0, memcmp(OO_list.data(), buff_span.data(), OO_list.size()));
     memset(buffer, 0, buff_span.size());
 
     // Verify Deserializing is properly filling out output extension field set for level control
@@ -651,17 +896,17 @@ TEST_F(TestSceneTable, TestHandlerFunctions)
     // Verify Encoding the Extension field set returns the same data as the one serialized for level control previously
     writer.Init(buff_span);
     EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), extensionFieldSetOut.attributeValueList));
-    EXPECT_EQ(0, memcmp(LC_list.data(), buff_span.data(), buff_span.size()));
+    EXPECT_EQ(0, memcmp(LC_list.data(), buff_span.data(), LC_list.size()));
     memset(buffer, 0, buff_span.size());
 
     // Verify Deserializing is properly filling out output extension field set for color control
-    EXPECT_TRUE(mpSceneHandler->SupportsCluster(kTestEndpoint1, kColorControlClusterId));
-    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->Deserialize(kTestEndpoint1, kColorControlClusterId, CC_list, extensionFieldSetOut));
+    EXPECT_TRUE(mpSceneHandler->SupportsCluster(kTestEndpoint2, kColorControlClusterId));
+    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->Deserialize(kTestEndpoint2, kColorControlClusterId, CC_list, extensionFieldSetOut));
 
     // Verify Encoding the Extension field set returns the same data as the one serialized for color control previously
     writer.Init(buff_span);
     EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), extensionFieldSetOut.attributeValueList));
-    EXPECT_EQ(0, memcmp(CC_list.data(), buff_span.data(), buff_span.size()));
+    EXPECT_EQ(0, memcmp(CC_list.data(), buff_span.data(), CC_list.size()));
     memset(buffer, 0, buff_span.size());
 
     // To test failure on serialize and deserialize when too many pairs are in the field sets
@@ -698,6 +943,353 @@ TEST_F(TestSceneTable, TestHandlerFunctions)
 
     memset(failBuffer, 0, fail_list.size());
     memset(buffer, 0, buff_span.size());
+
+    // Test Serialize Add of an attribute value that is greater than the mock attribute max (Max bool value)
+    OOPairs[0].valueUnsigned8.SetValue(0xFF);
+
+    // EFS to test caping of value once a variable above the mock attribute size is serialized
+    app::Clusters::ScenesManagement::Structs::ExtensionFieldSet::Type extensionFieldValueCapOut;
+    app::Clusters::ScenesManagement::Structs::ExtensionFieldSet::DecodableType extensionFieldValueCapIn;
+
+    extensionFieldValueCapOut.clusterID          = kOnOffClusterId;
+    extensionFieldValueCapOut.attributeValueList = OOPairs;
+
+    /// Setup of input EFS (by temporary using the output one)
+    writer.Init(buff_span);
+    EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), extensionFieldValueCapOut.attributeValueList));
+
+    reader.Init(buffer);
+    extensionFieldValueCapIn.clusterID = kOnOffClusterId;
+    EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+    EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+    // Verify that the initial value is not capped
+    auto pair_iterator = extensionFieldValueCapIn.attributeValueList.begin();
+    pair_iterator.Next();
+    app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type pair = pair_iterator.GetValue();
+    EXPECT_EQ(pair.valueUnsigned8.Value(), OOPairs[0].valueUnsigned8.Value());
+
+    // Verify that we cap the value to the mock attribute size when serializing
+    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint1, extensionFieldValueCapIn, buff_span));
+    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->Deserialize(kTestEndpoint1, kOnOffClusterId, buff_span, extensionFieldValueCapOut));
+
+    // Verify that the output value is capped to 1
+    EXPECT_EQ(1, extensionFieldValueCapOut.attributeValueList[0].valueUnsigned8.Value());
+
+    // Clear buffer
+    memset(buffer, 0, buff_span.size());
+
+    // Test Serialize Add of an attribute value that is smaller than the mock attribute min (1) for LC current level
+    LCPairs[0].valueUnsigned8.SetValue(0);
+
+    extensionFieldValueCapOut.clusterID          = kLevelControlClusterId;
+    extensionFieldValueCapOut.attributeValueList = LCPairs;
+
+    /// Setup of input EFS (by temporary using the output one)
+    buff_span = MutableByteSpan(buffer);
+    writer.Init(buff_span);
+    EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), extensionFieldValueCapOut.attributeValueList));
+
+    reader.Init(buffer);
+    extensionFieldValueCapIn.clusterID = kLevelControlClusterId;
+    EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+    EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+    // Verify that the initial value is not capped
+    auto iteratorMin = extensionFieldValueCapIn.attributeValueList.begin();
+    iteratorMin.Next();
+    pair = iteratorMin.GetValue();
+    EXPECT_EQ(pair.valueUnsigned8.Value(), LCPairs[0].valueUnsigned8.Value());
+
+    // Verify that we cap the value to the mock attribute size when serializing
+    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint1, extensionFieldValueCapIn, buff_span));
+    EXPECT_EQ(CHIP_NO_ERROR,
+              mpSceneHandler->Deserialize(kTestEndpoint1, kLevelControlClusterId, buff_span, extensionFieldValueCapOut));
+
+    // Verify that the output value is capped to 255 (NULL) as Level Control Current Level is a nullable uint8_t
+    EXPECT_EQ(255, extensionFieldValueCapOut.attributeValueList[0].valueUnsigned8.Value());
+
+    // Clear buffer
+    memset(buffer, 0, buff_span.size());
+
+    // Test Serialize Add of an attribute value that is higher than the mock attribute max (0xFE) for LC current level
+    LCPairs[0].valueUnsigned8.SetValue(0xFF);
+
+    extensionFieldValueCapOut.clusterID          = kLevelControlClusterId;
+    extensionFieldValueCapOut.attributeValueList = LCPairs;
+
+    /// Setup of input EFS (by temporary using the output one)
+    buff_span = MutableByteSpan(buffer);
+    writer.Init(buff_span);
+    EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), extensionFieldValueCapOut.attributeValueList));
+
+    reader.Init(buffer);
+    extensionFieldValueCapIn.clusterID = kLevelControlClusterId;
+    EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+    EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+    // Verify that the initial value is not capped
+    auto iteratorMax = extensionFieldValueCapIn.attributeValueList.begin();
+    iteratorMax.Next();
+    pair = iteratorMax.GetValue();
+    EXPECT_EQ(pair.valueUnsigned8.Value(), LCPairs[0].valueUnsigned8.Value());
+    EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint1, extensionFieldValueCapIn, buff_span));
+    EXPECT_EQ(CHIP_NO_ERROR,
+              mpSceneHandler->Deserialize(kTestEndpoint1, kLevelControlClusterId, buff_span, extensionFieldValueCapOut));
+
+    // Verify that the output value is 0xFF (NULL) as Level Control Current Level is a nullable uint8_t
+    EXPECT_EQ(0xFF, extensionFieldValueCapOut.attributeValueList[0].valueUnsigned8.Value());
+
+    // Clear buffer
+    memset(buffer, 0, buff_span.size());
+    buff_span = MutableByteSpan(buffer);
+
+    // Test for attribtues types that are in no Real clusters yet but are supported in scenes
+    {
+        // Setup EFS for mock cluster testing all attributes types
+        app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type MockOOPairs[1];
+        app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type MockLCPairs[2];
+        app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type MockCCPairs[9];
+        app::Clusters::ScenesManagement::Structs::AttributeValuePairStruct::Type MockFKPairs[2];
+        // Mock CC
+        MockCCPairs[0].attributeID = MockAttributeId(kCurrentSaturationId);
+        MockCCPairs[0].valueUnsigned32.SetValue(UINT32_MAX); // will cap to 0x00FFFFFF (uint24)
+        MockCCPairs[1].attributeID = MockAttributeId(kCurrentXId);
+        MockCCPairs[1].valueUnsigned32.SetValue(UINT32_MAX); // not capped
+        MockCCPairs[2].attributeID = MockAttributeId(kCurrentYId);
+        MockCCPairs[2].valueUnsigned64.SetValue(UINT64_MAX); // will cap to 0x0000FFFFFFFFFFFF (uint48)
+        MockCCPairs[3].attributeID = MockAttributeId(kColorTemperatureMiredsId);
+        MockCCPairs[3].valueUnsigned64.SetValue(UINT64_MAX); // will cap to 0x00FFFFFFFFFFFFFF (uint56)
+        MockCCPairs[4].attributeID = MockAttributeId(kEnhancedCurrentHueId);
+        MockCCPairs[4].valueUnsigned64.SetValue(UINT64_MAX); // not capped
+        MockCCPairs[5].attributeID = MockAttributeId(kEnhancedColorMode);
+        MockCCPairs[5].valueSigned8.SetValue(static_cast<int8_t>(-2)); // will cap to -1
+        MockCCPairs[6].attributeID = MockAttributeId(kColorLoopActiveId);
+        MockCCPairs[6].valueSigned16.SetValue(
+            static_cast<int16_t>(0x7FFE)); // will cap to 0x7FFD in int16 due to declared maximum in the attribute's mock metadata
+        MockCCPairs[7].attributeID = MockAttributeId(kColorLoopDirectionId);
+        MockCCPairs[7].valueSigned32.SetValue(-1); // will cap to -1 in int24
+        MockCCPairs[8].attributeID = MockAttributeId(kColorLoopTimeId);
+        MockCCPairs[8].valueSigned32.SetValue(-1); // not capped
+        // Mock OO
+        MockOOPairs[0].attributeID = MockAttributeId(kOnOffAttId);
+        MockOOPairs[0].valueSigned64.SetValue(INT64_MAX); // will cap to 0x00007FFFFFFFFFFF (int48)
+        // Mock LC
+        MockLCPairs[0].attributeID = MockAttributeId(kCurrentLevelId);
+        MockLCPairs[0].valueSigned64.SetValue(INT64_MIN); // will cap to 0x0080000000000000 (int56 min)
+        MockLCPairs[1].attributeID = MockAttributeId(kCurrentFrequencyId);
+        MockLCPairs[1].valueSigned64.SetValue(INT64_MIN); // not capped
+        // Mock Fake
+        MockFKPairs[0].attributeID = MockAttributeId(kCurrentLevelId);
+        MockFKPairs[0].valueUnsigned64.SetValue(UINT64_MAX); // will cap to UINT40_MAX
+        MockFKPairs[1].attributeID = MockAttributeId(kCurrentFrequencyId);
+        MockFKPairs[1].valueSigned64.SetValue(INT64_MAX); // will cap to INT40_MIN
+
+        // Initialize Extension Field sets as if they were received by add commands
+        OOextensionFieldSet.clusterID          = MockClusterId(kOnOffClusterId);
+        OOextensionFieldSet.attributeValueList = MockOOPairs;
+        LCextensionFieldSet.clusterID          = MockClusterId(kLevelControlClusterId);
+        LCextensionFieldSet.attributeValueList = MockLCPairs;
+        CCextensionFieldSet.clusterID          = MockClusterId(kColorControlClusterId);
+        CCextensionFieldSet.attributeValueList = MockCCPairs;
+
+        uint8_t mock_OO_buffer[scenes::kMaxFieldBytesPerCluster]     = { 0 };
+        uint8_t mock_LC_buffer[scenes::kMaxFieldBytesPerCluster]     = { 0 };
+        uint8_t mock_CC_buffer[scenes::kMaxFieldBytesPerCluster * 2] = {
+            0
+        }; // Using mock attributes way bigger than the real ones so we increase the buffer size for this test
+        ByteSpan Mock_OO_list(mock_OO_buffer);
+        ByteSpan Mock_LC_list(mock_LC_buffer);
+        ByteSpan Mock_CC_list(mock_CC_buffer);
+
+        // Serialize Extension Field sets as if they were recovered from memory
+        writer.Init(mock_OO_buffer);
+        EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), OOextensionFieldSet.attributeValueList));
+        OO_buffer_serialized_length = writer.GetLengthWritten();
+
+        writer.Init(mock_LC_buffer);
+        EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), LCextensionFieldSet.attributeValueList));
+        LC_buffer_serialized_length = writer.GetLengthWritten();
+
+        writer.Init(mock_CC_buffer);
+        EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), CCextensionFieldSet.attributeValueList));
+        CC_buffer_serialized_length = writer.GetLengthWritten();
+
+        // Setup the On Off Extension field set in the expected state from a command
+        reader.Init(Mock_OO_list);
+        extensionFieldValueCapIn.clusterID = MockClusterId(kOnOffClusterId);
+        EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+        EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+        // Verify that the initial value is not capped
+        auto iteratorOO = extensionFieldValueCapIn.attributeValueList.begin();
+        iteratorOO.Next();
+        pair = iteratorOO.GetValue();
+        EXPECT_EQ(pair.valueSigned64.Value(), MockOOPairs[0].valueSigned64.Value());
+
+        // Verify that we cap the value to the mock attribute size when serializing
+        EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint4, extensionFieldValueCapIn, buff_span));
+        EXPECT_EQ(
+            CHIP_NO_ERROR,
+            mpSceneHandler->Deserialize(kTestEndpoint4, MockClusterId(kOnOffClusterId), buff_span, extensionFieldValueCapOut));
+
+        // Verify that the output value is capped to int48 max value
+        int64_t int48Max = static_cast<int64_t>(0x00007FFFFFFFFFFF);
+        EXPECT_EQ(int48Max, extensionFieldValueCapOut.attributeValueList[0].valueSigned64.Value());
+
+        // Clear buffer
+        memset(buffer, 0, buff_span.size());
+        // Reinit buffer
+        buff_span = MutableByteSpan(buffer);
+
+        reader.Init(Mock_LC_list);
+        extensionFieldValueCapIn.clusterID = MockClusterId(kLevelControlClusterId);
+        EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+        EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+        // Verify that the initial values are not capped
+        auto iteratorLC = extensionFieldValueCapIn.attributeValueList.begin();
+        iteratorLC.Next();
+        pair = iteratorLC.GetValue();
+        EXPECT_EQ(pair.valueSigned64.Value(), MockLCPairs[0].valueSigned64.Value());
+        iteratorLC.Next();
+        pair = iteratorLC.GetValue();
+        EXPECT_EQ(pair.valueSigned64.Value(), MockLCPairs[1].valueSigned64.Value());
+
+        // Verify that we cap the value to the mock attribute size when serializing
+        EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint4, extensionFieldValueCapIn, buff_span));
+        EXPECT_EQ(CHIP_NO_ERROR,
+                  mpSceneHandler->Deserialize(kTestEndpoint4, MockClusterId(kLevelControlClusterId), buff_span,
+                                              extensionFieldValueCapOut));
+
+        // Verify that the output value is capped to int56 min value
+        int64_t int56Min = static_cast<int64_t>(0xFF80000000000000);
+        EXPECT_EQ(int56Min, static_cast<int64_t>(extensionFieldValueCapOut.attributeValueList[0].valueSigned64.Value()));
+
+        // Verify that the output value is not capped
+        EXPECT_EQ(INT64_MIN, extensionFieldValueCapOut.attributeValueList[1].valueSigned64.Value());
+
+        // Clear buffer
+        memset(buffer, 0, buff_span.size());
+        // Reinit buffer
+        buff_span = MutableByteSpan(buffer);
+
+        reader.Init(Mock_CC_list);
+        extensionFieldValueCapIn.clusterID = MockClusterId(kColorControlClusterId);
+        EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+        EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+        // Verify that the initial values are not capped
+        auto iteratorCC = extensionFieldValueCapIn.attributeValueList.begin();
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueUnsigned32.Value(), MockCCPairs[0].valueUnsigned32.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueUnsigned32.Value(), MockCCPairs[1].valueUnsigned32.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueUnsigned64.Value(), MockCCPairs[2].valueUnsigned64.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueUnsigned64.Value(), MockCCPairs[3].valueUnsigned64.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueUnsigned64.Value(), MockCCPairs[4].valueUnsigned64.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueSigned8.Value(), MockCCPairs[5].valueSigned8.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueSigned16.Value(), MockCCPairs[6].valueSigned16.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueSigned32.Value(), MockCCPairs[7].valueSigned32.Value());
+        iteratorCC.Next();
+        pair = iteratorCC.GetValue();
+        EXPECT_EQ(pair.valueSigned32.Value(), MockCCPairs[8].valueSigned32.Value());
+
+        // Verify that we cap the value to the mock attribute size when serializing
+        EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint4, extensionFieldValueCapIn, buff_span));
+        EXPECT_EQ(CHIP_NO_ERROR,
+                  mpSceneHandler->Deserialize(kTestEndpoint4, MockClusterId(kColorControlClusterId), buff_span,
+                                              extensionFieldValueCapOut));
+
+        // Verify that the output value is capped to uint24t max value
+        uint32_t uint24Max = static_cast<uint32_t>(0x00FFFFFF);
+        EXPECT_EQ(uint24Max, extensionFieldValueCapOut.attributeValueList[0].valueUnsigned32.Value());
+
+        // Verify that the output value is not capped
+        EXPECT_EQ(UINT32_MAX, extensionFieldValueCapOut.attributeValueList[1].valueUnsigned32.Value());
+
+        // Verify that the output value is capped to int48_t max value
+        uint64_t uint48Max = static_cast<uint64_t>(0x0000FFFFFFFFFFFF);
+        EXPECT_EQ(uint48Max, extensionFieldValueCapOut.attributeValueList[2].valueUnsigned64.Value());
+
+        // Verify that the output value is capped to int56_t max value
+        uint64_t uint56Max = static_cast<uint64_t>(0x00FFFFFFFFFFFFFF);
+        EXPECT_EQ(uint56Max, extensionFieldValueCapOut.attributeValueList[3].valueUnsigned64.Value());
+
+        // Verify that the output value is not capped
+        EXPECT_EQ(UINT64_MAX, extensionFieldValueCapOut.attributeValueList[4].valueUnsigned64.Value());
+
+        // Verify that the output value is capped to the defined min for this attribute
+        EXPECT_EQ(static_cast<int8_t>(-1), extensionFieldValueCapOut.attributeValueList[5].valueSigned8.Value());
+
+        // Verify that the output value is capped to the defined max for this attribute
+        EXPECT_EQ(0x7FFD, extensionFieldValueCapOut.attributeValueList[6].valueSigned16.Value());
+
+        // Verify that the output value is not capped to -1 in int24t
+        using Int24Type = app::NumericAttributeTraits<app::OddSizedInteger<3, true>>::WorkingType;
+        EXPECT_EQ(static_cast<Int24Type>(-1), extensionFieldValueCapOut.attributeValueList[7].valueSigned32.Value());
+
+        // Verify that the output value will not cap
+        EXPECT_EQ(-1, extensionFieldValueCapOut.attributeValueList[8].valueSigned32.Value());
+
+        // Clear buffer
+        memset(buffer, 0, buff_span.size());
+
+        LCextensionFieldSet.clusterID          = MockClusterId(kFakeClusterId);
+        LCextensionFieldSet.attributeValueList = MockFKPairs;
+
+        writer.Init(mock_LC_buffer);
+        EXPECT_EQ(CHIP_NO_ERROR, app::DataModel::Encode(writer, TLV::AnonymousTag(), LCextensionFieldSet.attributeValueList));
+        LC_buffer_serialized_length = writer.GetLengthWritten();
+
+        // Reinit buffer
+        buff_span = MutableByteSpan(buffer);
+
+        reader.Init(Mock_LC_list);
+        extensionFieldValueCapIn.clusterID = MockClusterId(kFakeClusterId);
+        EXPECT_EQ(CHIP_NO_ERROR, reader.Next());
+        EXPECT_EQ(CHIP_NO_ERROR, extensionFieldValueCapIn.attributeValueList.Decode(reader));
+
+        // Verify that the initial values are not capped
+        auto iteratorFK = extensionFieldValueCapIn.attributeValueList.begin();
+        iteratorFK.Next();
+        pair = iteratorFK.GetValue();
+        EXPECT_EQ(pair.valueUnsigned64.Value(), MockFKPairs[0].valueUnsigned64.Value());
+        iteratorFK.Next();
+        pair = iteratorFK.GetValue();
+        EXPECT_EQ(pair.valueSigned64.Value(), MockFKPairs[1].valueSigned64.Value());
+
+        // Verify that we cap the value to the mock attribute size when serializing
+        EXPECT_EQ(CHIP_NO_ERROR, mpSceneHandler->SerializeAdd(kTestEndpoint4, extensionFieldValueCapIn, buff_span));
+        EXPECT_EQ(CHIP_NO_ERROR,
+                  mpSceneHandler->Deserialize(kTestEndpoint4, MockClusterId(kFakeClusterId), buff_span, extensionFieldValueCapOut));
+
+        // Verify that the output value is capped to uint40 max value
+        uint64_t uint40Max = static_cast<uint64_t>(0x000000FFFFFFFFFF);
+        EXPECT_EQ(uint40Max, extensionFieldValueCapOut.attributeValueList[0].valueUnsigned64.Value());
+
+        // Verify that the output value is capped to int40 max value
+        int64_t int40Max = static_cast<int64_t>(0x0000007FFFFFFFFF);
+        EXPECT_EQ(int40Max, extensionFieldValueCapOut.attributeValueList[1].valueSigned64.Value());
+
+        // Clear buffer
+        memset(buffer, 0, buff_span.size());
+        // Reinit buffer
+    }
 };
 
 TEST_F(TestSceneTable, TestStoreScenes)
diff --git a/src/app/tests/suites/certification/Test_TC_S_2_2.yaml b/src/app/tests/suites/certification/Test_TC_S_2_2.yaml
index bdb3d2b8ad90db..49ce0cdb23c85f 100644
--- a/src/app/tests/suites/certification/Test_TC_S_2_2.yaml
+++ b/src/app/tests/suites/certification/Test_TC_S_2_2.yaml
@@ -480,6 +480,20 @@ tests:
       response:
           error: CONSTRAINT_ERROR
 
+    - label:
+          "Step 4f: TH sends a RecallScene command to DUT with the GroupID field
+          set to GI (Where GI is a group currently absent from the group table)
+          and the SceneID field set to 0x01."
+      command: "RecallScene"
+      arguments:
+          values:
+              - name: "GroupID"
+                value: GI
+              - name: "SceneID"
+                value: 0x01
+      response:
+          error: INVALID_COMMAND
+
     - label:
           "Step 5a: TH sends a ViewScene command to DUT with the GroupID field
           set to G1 and the SceneID field set to 0x01."
@@ -872,6 +886,78 @@ tests:
               - name: "SceneID"
                 value: 0xFF
 
+    - label:
+          "Step 8g: TH sends a AddScene command to DUT with the GroupID field
+          set to G1, the SceneID field set to 0x01, the TransitionTime field set
+          to 1000 (1s) and extension field sets holding an invalid
+          ExtensionField (Unscenable attribute ID for given cluster). This
+          should fail and return a status of 0x85 (INVALID_COMMAND)."
+      ## TODO: Change test to test for an existing bu non scenable attribute ID once scenability check is possible, see issue: https://github.com/project-chip/connectedhomeip/issues/24177
+      PICS: S.S.C00.Rsp && PICS_SDK_CI_ONLY
+      command: "AddScene"
+      arguments:
+          values:
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x01
+              - name: "TransitionTime"
+                value: 1000
+              - name: "SceneName"
+                value: "Scene1"
+              - name: "ExtensionFieldSets"
+                value:
+                    [
+                        {
+                            ClusterID: 0x0006,
+                            AttributeValueList:
+                                [{ AttributeID: 0x4011, ValueUnsigned8: 0x01 }],
+                        },
+                    ]
+      response:
+          values:
+              - name: "Status"
+                value: 0x85
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x01
+
+    - label:
+          "Step 8g: TH sends a AddScene command to DUT with the GroupID field
+          set to G1, the SceneID field set to 0x01, the TransitionTime field set
+          to 1000 (1s) and extension field sets holding an invalid
+          ExtensionField (Unscenable attribute ID for given cluster). This
+          should fail and return a status of 0x85 (INVALID_COMMAND)."
+      ## TODO: Change test to test for an existing bu non scenable attribute ID once scenability check is possible, see issue: https://github.com/project-chip/connectedhomeip/issues/24177
+      verification: |
+          ./chip-tool scenesmanagement add-scene 0x0001 0x01 1000 "scene name" '[{"clusterID": "0x006", "attributeValueList":[{"attributeID": "0x4001", "attributeValue": "0x01"}]}]' 1 1
+
+          Verify DUT sends a AddSceneResponse command to TH with the Status field set to 0x85 (INVALID_COMMAND), the GroupID field set to G1 and the SceneID field set to 0x01 on the TH(Chip-tool)
+          Log and below is the sample log provided for the raspi platform:
+
+          [1706763610.675038][4232:4234] CHIP:DMG: },
+          [1706763610.675108][4232:4234] CHIP:DMG: Received Command Response Data, Endpoint=1 Cluster=0x0000_0062 Command=0x0000_0000
+          [1706763610.675134][4232:4234] CHIP:TOO: Endpoint: 1 Cluster: 0x0000_0062 Command 0x0000_0000
+          [1706763610.675187][4232:4234] CHIP:TOO:   AddSceneResponse: {
+          [1706763610.675215][4232:4234] CHIP:TOO:     status: 133
+          [1706763610.675229][4232:4234] CHIP:TOO:     groupID: 1
+          [1706763610.675244][4232:4234] CHIP:TOO:     sceneID: 1
+          [1706763610.675258][4232:4234] CHIP:TOO:    }
+      cluster: "LogCommands"
+      command: "UserPrompt"
+      PICS: PICS_SKIP_SAMPLE_APP
+      arguments:
+          values:
+              - name: "message"
+                value:
+                    "Please execute the add scene command with an invalid
+                    extensionfieldsets due to a non sceneable attribute not in
+                    an extensionfieldset on DUT and enter 'y' if the command
+                    returned a status of 0x85 (INVALID_COMMAND)"
+              - name: "expectedValue"
+                value: "y"
+
     - label:
           "Step 9a: TH sends a RemoveScene command to DUT with the GroupID field
           set to G1 and the SceneID field set to 0x01."
diff --git a/src/app/tests/suites/certification/Test_TC_S_2_3.yaml b/src/app/tests/suites/certification/Test_TC_S_2_3.yaml
index 5a76916edb39b7..6cf2bb77479cee 100644
--- a/src/app/tests/suites/certification/Test_TC_S_2_3.yaml
+++ b/src/app/tests/suites/certification/Test_TC_S_2_3.yaml
@@ -705,6 +705,81 @@ tests:
               - name: "SceneID"
                 value: 0x03
 
+    - label:
+          "Step 6f: TH sends a StoreScene command to to group G1 with the
+          GroupID field set to G1 and the SceneID field set to 0x03."
+      PICS: S.S.C04.Rsp
+      command: "StoreScene"
+      groupId: G1
+      arguments:
+          values:
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x03
+
+    - label:
+          "Step 6g: TH sends a ViewScene command to DUT with the GroupID field
+          set to G1 and the SceneID field set to 0x03."
+      PICS: S.S.C01.Rsp
+      command: "ViewScene"
+      arguments:
+          values:
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x03
+      response:
+          values:
+              - name: "Status"
+                value: 0x00
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x03
+
+    - label:
+          "Step 6h: TH sends a RemoveScene command to group G1 with the GroupID
+          field set to G1 and the SceneID field set to 0x03."
+      PICS: S.S.C02.Rsp
+      command: "RemoveScene"
+      groupId: G1
+      arguments:
+          values:
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x03
+
+    - label: "Wait 1+ s to give CI time to process the RemoveScene command."
+      PICS: PICS_SDK_CI_ONLY
+      cluster: "DelayCommands"
+      command: "WaitForMs"
+      arguments:
+          values:
+              - name: "ms"
+                value: 1250
+
+    - label:
+          "Step 6i: TH sends a ViewScene command to DUT with the GroupID field
+          set to G1 and the SceneID field set to 0x03."
+      PICS: S.S.C01.Rsp
+      command: "ViewScene"
+      arguments:
+          values:
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x03
+      response:
+          values:
+              - name: "Status"
+                value: 0x8b
+              - name: "GroupID"
+                value: G1
+              - name: "SceneID"
+                value: 0x03
+
     - label:
           "Step 7a: TH sends a CopyScene command to DUT with the mode field set
           to 0x00, the group identifier from field set to G1, the scene
diff --git a/src/app/util/attribute-metadata.h b/src/app/util/attribute-metadata.h
index a380599a8f48b6..1a2b2fd04ed447 100644
--- a/src/app/util/attribute-metadata.h
+++ b/src/app/util/attribute-metadata.h
@@ -17,8 +17,8 @@
 
 #pragma once
 
+#include <app-common/zap-generated/attribute-type.h>
 #include <app/util/basic-types.h>
-
 #include <cstdint>
 
 /**
@@ -158,6 +158,25 @@ struct EmberAfAttributeMetadata
      */
     EmberAfAttributeMask mask;
 
+    /**
+     * Check wether this attribute is a boolean based on its type according to the spec.
+     */
+    bool IsBoolean() const { return attributeType == ZCL_BOOLEAN_ATTRIBUTE_TYPE; }
+
+    /**
+     * Check wether this attribute is signed based on its type according to the spec.
+     */
+    bool IsSignedIntegerAttribute() const
+    {
+        return (attributeType >= ZCL_INT8S_ATTRIBUTE_TYPE && attributeType <= ZCL_INT64S_ATTRIBUTE_TYPE) ||
+            attributeType == ZCL_TEMPERATURE_ATTRIBUTE_TYPE;
+    }
+
+    /**
+     * Check whether this attribute has a define min and max.
+     */
+    bool HasMinMax() const { return mask & ATTRIBUTE_MASK_MIN_MAX; }
+
     /**
      * Check whether this attribute is nullable.
      */
diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp
index 211d2a19123dbd..ab59e56016e544 100644
--- a/src/app/util/attribute-table.cpp
+++ b/src/app/util/attribute-table.cpp
@@ -41,13 +41,6 @@ using namespace chip;
 using namespace chip::app;
 
 namespace {
-// Zigbee spec says types between signed 8 bit and signed 64 bit
-bool emberAfIsTypeSigned(EmberAfAttributeType dataType)
-{
-    return (dataType >= ZCL_INT8S_ATTRIBUTE_TYPE && dataType <= ZCL_INT64S_ATTRIBUTE_TYPE) ||
-        dataType == ZCL_TEMPERATURE_ATTRIBUTE_TYPE;
-}
-
 /**
  * @brief Simple integer comparison function.
  * Compares two values of a known length as integers.
@@ -386,7 +379,7 @@ Status emAfWriteAttribute(EndpointId endpoint, ClusterId cluster, AttributeId at
             maxBytes = maxv.ptrToDefaultValue;
         }
 
-        bool isAttributeSigned = emberAfIsTypeSigned(metadata->attributeType);
+        bool isAttributeSigned = metadata->IsSignedIntegerAttribute();
         bool isOutOfRange      = emberAfCompareValues(minBytes, data, dataLen, isAttributeSigned) == 1 ||
             emberAfCompareValues(maxBytes, data, dataLen, isAttributeSigned) == -1;
 
diff --git a/src/app/util/mock/MockNodeConfig.h b/src/app/util/mock/MockNodeConfig.h
index 10110604678c20..668d81478d4659 100644
--- a/src/app/util/mock/MockNodeConfig.h
+++ b/src/app/util/mock/MockNodeConfig.h
@@ -53,6 +53,7 @@ constexpr EmberAfAttributeMetadata DefaultAttributeMetadata(chip::AttributeId id
 struct MockAttributeConfig
 {
     MockAttributeConfig(AttributeId aId) : id(aId), attributeMetaData(internal::DefaultAttributeMetadata(aId)) {}
+    MockAttributeConfig(AttributeId aId, EmberAfAttributeMetadata metadata) : id(aId), attributeMetaData(metadata) {}
     MockAttributeConfig(AttributeId aId, EmberAfAttributeType type,
                         EmberAfAttributeMask mask = ATTRIBUTE_MASK_WRITABLE | ATTRIBUTE_MASK_NULLABLE) :
         id(aId),