diff --git a/Server/mods/deathmatch/local.conf b/Server/mods/deathmatch/local.conf
index 99b97bee078..039e155d819 100644
--- a/Server/mods/deathmatch/local.conf
+++ b/Server/mods/deathmatch/local.conf
@@ -268,6 +268,12 @@
           Values: 0 - Off, 1 - Enabled.  Default - 1 -->
     1
 
+    
+    0
+
     
     
diff --git a/Server/mods/deathmatch/logic/CCustomData.cpp b/Server/mods/deathmatch/logic/CCustomData.cpp
index f18bbd37d19..545df5a0c35 100644
--- a/Server/mods/deathmatch/logic/CCustomData.cpp
+++ b/Server/mods/deathmatch/logic/CCustomData.cpp
@@ -21,7 +21,7 @@ void CCustomData::Copy(CCustomData* pCustomData)
     }
 }
 
-SCustomData* CCustomData::Get(const char* szName)
+SCustomData* CCustomData::Get(const char* szName) const
 {
     assert(szName);
 
@@ -100,6 +100,7 @@ void CCustomData::Set(const char* szName, const CLuaArgument& Variable, ESyncTyp
         SCustomData newData;
         newData.Variable = Variable;
         newData.syncType = syncType;
+        newData.clientChangesMode = eCustomDataClientTrust::UNSET;
         m_Data[szName] = newData;
         UpdateSynced(szName, Variable, syncType);
     }
@@ -120,6 +121,12 @@ bool CCustomData::Delete(const char* szName)
     return false;
 }
 
+void CCustomData::SetClientChangesMode(const char* szName, eCustomDataClientTrust mode)
+{
+    SCustomData& pData = m_Data[szName];
+    pData.clientChangesMode = mode;
+}
+
 CXMLNode* CCustomData::OutputToXML(CXMLNode* pNode)
 {
     std::map::const_iterator iter = m_Data.begin();
diff --git a/Server/mods/deathmatch/logic/CCustomData.h b/Server/mods/deathmatch/logic/CCustomData.h
index bfb17ff5290..887ef34dee9 100644
--- a/Server/mods/deathmatch/logic/CCustomData.h
+++ b/Server/mods/deathmatch/logic/CCustomData.h
@@ -25,10 +25,18 @@ enum class ESyncType
     SUBSCRIBE,
 };
 
+enum class eCustomDataClientTrust : std::uint8_t
+{
+    UNSET,
+    ALLOW,
+    DENY,
+};
+
 struct SCustomData
 {
-    CLuaArgument Variable;
-    ESyncType    syncType;
+    CLuaArgument           Variable;
+    ESyncType              syncType;
+    eCustomDataClientTrust clientChangesMode;
 };
 
 class CCustomData
@@ -36,12 +44,14 @@ class CCustomData
 public:
     void Copy(CCustomData* pCustomData);
 
-    SCustomData* Get(const char* szName);
+    SCustomData* Get(const char* szName) const;
     SCustomData* GetSynced(const char* szName);
     void         Set(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST);
 
     bool Delete(const char* szName);
 
+    void SetClientChangesMode(const char* szName, eCustomDataClientTrust mode);
+
     unsigned short CountOnlySynchronized();
 
     CXMLNode* OutputToXML(CXMLNode* pNode);
diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp
index 59086a2f143..79a051b5458 100644
--- a/Server/mods/deathmatch/logic/CElement.cpp
+++ b/Server/mods/deathmatch/logic/CElement.cpp
@@ -508,7 +508,7 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node)
     }
 }
 
-CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType)
+CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType, eCustomDataClientTrust* clientChangesMode)
 {
     assert(szName);
 
@@ -518,13 +518,17 @@ CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESy
     {
         if (pSyncType)
             *pSyncType = pData->syncType;
+
+        if (clientChangesMode)
+            *clientChangesMode = pData->clientChangesMode;
+
         return &pData->Variable;
     }
 
     // If none, try returning parent's custom data
     if (bInheritData && m_pParent)
     {
-        return m_pParent->GetCustomData(szName, true, pSyncType);
+        return m_pParent->GetCustomData(szName, true, pSyncType, clientChangesMode);
     }
 
     // None available
diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h
index e3a0fa4d070..802981cd5a8 100644
--- a/Server/mods/deathmatch/logic/CElement.h
+++ b/Server/mods/deathmatch/logic/CElement.h
@@ -136,7 +136,7 @@ class CElement
 
     void           ReadCustomData(CEvents* pEvents, CXMLNode& Node);
     CCustomData&   GetCustomDataManager() { return m_CustomData; }
-    CLuaArgument*  GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType = NULL);
+    CLuaArgument*  GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType = nullptr, eCustomDataClientTrust* clientChangesMode = nullptr);
     CLuaArguments* GetAllCustomData(CLuaArguments* table);
     bool           GetCustomDataString(const char* szName, char* pOut, size_t sizeBuffer, bool bInheritData);
     bool           GetCustomDataInt(const char* szName, int& iOut, bool bInheritData);
diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp
index d4efea393f4..9543e1e4474 100644
--- a/Server/mods/deathmatch/logic/CGame.cpp
+++ b/Server/mods/deathmatch/logic/CGame.cpp
@@ -1607,6 +1607,7 @@ void CGame::AddBuiltInEvents()
     m_Events.AddEvent("onPlayerTriggerEventThreshold", "", nullptr, false);
     m_Events.AddEvent("onPlayerTeamChange", "oldTeam, newTeam", nullptr, false);
     m_Events.AddEvent("onPlayerTriggerInvalidEvent", "eventName, isAdded, isRemote", nullptr, false);
+    m_Events.AddEvent("onPlayerChangesProtectedData", "element, key, value", nullptr, false);
 
     // Ped events
     m_Events.AddEvent("onPedVehicleEnter", "vehicle, seat, jacked", NULL, false);
@@ -2652,7 +2653,24 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet)
             }
 
             ESyncType lastSyncType = ESyncType::BROADCAST;
-            pElement->GetCustomData(szName, false, &lastSyncType);
+            eCustomDataClientTrust clientChangesMode{};
+
+            pElement->GetCustomData(szName, false, &lastSyncType, &clientChangesMode);
+
+            const bool changesAllowed = clientChangesMode == eCustomDataClientTrust::UNSET ? !m_pMainConfig->IsElementDataWhitelisted()
+                                                                                           : clientChangesMode == eCustomDataClientTrust::ALLOW;
+            if (!changesAllowed)
+            {
+                CLogger::ErrorPrintf("Client trying to change protected element data %s (%s)", Packet.GetSourcePlayer()->GetNick(),
+                                     szName);
+
+                CLuaArguments arguments;
+                arguments.PushElement(pElement);
+                arguments.PushString(szName);
+                arguments.PushArgument(Value);
+                pSourcePlayer->CallEvent("onPlayerChangesProtectedData", arguments);
+                return;
+            }
 
             if (lastSyncType != ESyncType::LOCAL)
             {
diff --git a/Server/mods/deathmatch/logic/CMainConfig.cpp b/Server/mods/deathmatch/logic/CMainConfig.cpp
index 4e6b84ce3f3..bece65e885f 100644
--- a/Server/mods/deathmatch/logic/CMainConfig.cpp
+++ b/Server/mods/deathmatch/logic/CMainConfig.cpp
@@ -79,6 +79,7 @@ CMainConfig::CMainConfig(CConsole* pConsole) : CXMLConfig(NULL)
     m_iBackupInterval = 3;
     m_iBackupAmount = 5;
     m_bSyncMapElementData = true;
+    m_elementDataWhitelisted = false;
 }
 
 bool CMainConfig::Load()
@@ -526,6 +527,8 @@ bool CMainConfig::Load()
         g_TickRateSettings.iLightSync = Clamp(200, g_TickRateSettings.iLightSync, 4000);
     }
 
+    GetBoolean(m_pRootNode, "elementdata_whitelisted", m_elementDataWhitelisted);
+
     ApplyNetOptions();
 
     return true;
diff --git a/Server/mods/deathmatch/logic/CMainConfig.h b/Server/mods/deathmatch/logic/CMainConfig.h
index 1ddb0c8645b..9758ae2dbfd 100644
--- a/Server/mods/deathmatch/logic/CMainConfig.h
+++ b/Server/mods/deathmatch/logic/CMainConfig.h
@@ -126,6 +126,7 @@ class CMainConfig : public CXMLConfig
     const std::vector& GetOwnerEmailAddressList() const { return m_OwnerEmailAddressList; }
     bool                        IsDatabaseCredentialsProtectionEnabled() const { return m_bDatabaseCredentialsProtectionEnabled != 0; }
     bool                        IsFakeLagCommandEnabled() const { return m_bFakeLagCommandEnabled != 0; }
+    bool                        IsElementDataWhitelisted() const { return m_elementDataWhitelisted; }
     bool                        IsCheckResourceClientFilesEnabled() const noexcept { return m_checkResourceClientFiles != 0; }
 
     SString GetSetting(const SString& configSetting);
@@ -228,5 +229,6 @@ class CMainConfig : public CXMLConfig
     int                        m_bFakeLagCommandEnabled;
     int                        m_iPlayerTriggeredEventIntervalMs;
     int                        m_iMaxPlayerTriggeredEventsPerInterval;
+    bool                       m_elementDataWhitelisted;
     int                        m_checkResourceClientFiles;
 };
diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
index 67764f80573..b4d1de641f5 100644
--- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
+++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
@@ -954,14 +954,19 @@ bool CStaticFunctionDefinitions::SetElementID(CElement* pElement, const char* sz
     return true;
 }
 
-bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType)
+bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType,
+                                                std::optional clientTrust)
 {
     assert(pElement);
     assert(szName);
     assert(strlen(szName) <= MAX_CUSTOMDATA_NAME_LENGTH);
 
-    ESyncType     lastSyncType = ESyncType::BROADCAST;
-    CLuaArgument* pCurrentVariable = pElement->GetCustomData(szName, false, &lastSyncType);
+    ESyncType              lastSyncType = ESyncType::BROADCAST;
+    eCustomDataClientTrust lastClientTrust{};
+    CLuaArgument*          pCurrentVariable = pElement->GetCustomData(szName, false, &lastSyncType, &lastClientTrust);
+
+    if (clientTrust.has_value() && lastClientTrust != clientTrust.value())
+        pElement->GetCustomDataManager().SetClientChangesMode(szName, clientTrust.value());
 
     if (!pCurrentVariable || *pCurrentVariable != Variable || lastSyncType != syncType)
     {
diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h
index dd6202208ff..8c947d6f343 100644
--- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h
+++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h
@@ -83,7 +83,8 @@ class CStaticFunctionDefinitions
     // Element set funcs
     static bool ClearElementVisibleTo(CElement* pElement);
     static bool SetElementID(CElement* pElement, const char* szID);
-    static bool SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType);
+    static bool SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType,
+                               std::optional clientTrust);
     static bool RemoveElementData(CElement* pElement, const char* szName);
     static bool AddElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer);
     static bool RemoveElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer);
diff --git a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp
index ef25750c053..76540327afb 100644
--- a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp
+++ b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp
@@ -285,6 +285,12 @@ ADD_ENUM(ESyncType::LOCAL, "local")
 ADD_ENUM(ESyncType::SUBSCRIBE, "subscribe")
 IMPLEMENT_ENUM_CLASS_END("sync-mode")
 
+IMPLEMENT_ENUM_CLASS_BEGIN(eCustomDataClientTrust)
+ADD_ENUM(eCustomDataClientTrust::UNSET, "default")
+ADD_ENUM(eCustomDataClientTrust::ALLOW, "allow")
+ADD_ENUM(eCustomDataClientTrust::DENY, "deny")
+IMPLEMENT_ENUM_CLASS_END("client-trust-mode")
+
 //
 // CResource from userdata
 //
diff --git a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h
index 52a4536012e..796ca3c7027 100644
--- a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h
+++ b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h
@@ -38,6 +38,7 @@ DECLARE_ENUM(CAccessControlListRight::ERightType);
 DECLARE_ENUM(CElement::EElementType);
 DECLARE_ENUM(CAccountPassword::EAccountPasswordType);
 DECLARE_ENUM_CLASS(ESyncType);
+DECLARE_ENUM_CLASS(eCustomDataClientTrust)
 
 enum eHudComponent
 {
diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp
index 6cacbdcc989..f8effd7b895 100644
--- a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp
+++ b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp
@@ -1538,6 +1538,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM)
     SString      strKey;
     CLuaArgument value;
     ESyncType    syncType = ESyncType::BROADCAST;
+    std::optional clientTrust{};
 
     CScriptArgReader argStream(luaVM);
     argStream.ReadUserData(pElement);
@@ -1554,6 +1555,13 @@ int CLuaElementDefs::setElementData(lua_State* luaVM)
     else
         argStream.ReadEnumString(syncType, ESyncType::BROADCAST);
 
+    if (!argStream.NextIsNone())
+    {
+        eCustomDataClientTrust trustReaded;
+        argStream.ReadEnumString(trustReaded);
+        clientTrust = trustReaded;
+    }
+
     if (!argStream.HasErrors())
     {
         LogWarningIfPlayerHasNotJoinedYet(luaVM, pElement);
@@ -1566,7 +1574,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM)
             strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH);
         }
 
-        if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType))
+        if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType, clientTrust))
         {
             lua_pushboolean(luaVM, true);
             return 1;
diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf
index 31faba9112d..11ef497fa78 100644
--- a/Server/mods/deathmatch/mtaserver.conf
+++ b/Server/mods/deathmatch/mtaserver.conf
@@ -268,6 +268,12 @@
          Values: 0 - Off, 1 - Enabled.  Default - 1 -->
     1
 
+     
+    0
+
     
     1
 
+    
+    0
+