diff --git a/include/behaviortree_cpp/basic_types.h b/include/behaviortree_cpp/basic_types.h
index 244f4b2a3..9dc98a902 100644
--- a/include/behaviortree_cpp/basic_types.h
+++ b/include/behaviortree_cpp/basic_types.h
@@ -342,6 +342,8 @@ struct Timestamp
 
 [[nodiscard]] bool IsAllowedPortName(StringView str);
 
+[[nodiscard]] bool IsNodeNameAttribute(StringView str);
+
 class TypeInfo
 {
 public:
diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h
index 537176519..ebc77cfed 100644
--- a/include/behaviortree_cpp/tree_node.h
+++ b/include/behaviortree_cpp/tree_node.h
@@ -41,6 +41,7 @@ struct TreeNodeManifest
 };
 
 using PortsRemapping = std::unordered_map<std::string, std::string>;
+using OtherAttributes = std::unordered_map<std::string, std::string>;
 
 enum class PreCond
 {
@@ -84,6 +85,9 @@ struct NodeConfig
   // output ports
   PortsRemapping output_ports;
 
+  // Any other attributes found in the xml that are not parsed as ports (e.g. anything with a leading '_')
+  OtherAttributes other_attributes;
+
   const TreeNodeManifest* manifest = nullptr;
 
   // Numberic unique identifier
diff --git a/src/basic_types.cpp b/src/basic_types.cpp
index 088a11015..8cb38cb96 100644
--- a/src/basic_types.cpp
+++ b/src/basic_types.cpp
@@ -433,11 +433,12 @@ bool IsAllowedPortName(StringView str)
   {
     return false;
   }
-  if(str == "name" || str == "ID")
-  {
-    return false;
-  }
-  return true;
+  return !IsNodeNameAttribute(str);
+}
+
+bool IsNodeNameAttribute(StringView str)
+{
+  return str == "name" || str == "ID";
 }
 
 Any convertFromJSON(StringView json_text, std::type_index type)
diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp
index 31e2f28f7..cf150331a 100644
--- a/src/xml_parsing.cpp
+++ b/src/xml_parsing.cpp
@@ -18,6 +18,7 @@
 #include <sstream>
 #include <string>
 #include <typeindex>
+#include "behaviortree_cpp/basic_types.h"
 
 #if defined(_MSVC_LANG) && !defined(__clang__)
 #define __bt_cplusplus (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
@@ -677,13 +678,13 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
   }
 
   PortsRemapping port_remap;
+  OtherAttributes other_attributes;
   for(const XMLAttribute* att = element->FirstAttribute(); att; att = att->Next())
   {
-    if(IsAllowedPortName(att->Name()))
+    const std::string port_name = att->Name();
+    const std::string port_value = att->Value();
+    if(IsAllowedPortName(port_name))
     {
-      const std::string port_name = att->Name();
-      const std::string port_value = att->Value();
-
       if(manifest)
       {
         auto port_model_it = manifest->ports.find(port_name);
@@ -721,6 +722,10 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
 
       port_remap[port_name] = port_value;
     }
+    else if(!IsNodeNameAttribute(port_name))
+    {
+      other_attributes[port_name] = port_value;
+    }
   }
 
   NodeConfig config;
@@ -738,6 +743,7 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
     if(auto script = element->Attribute(attr_name))
     {
       conditions.insert({ ID, std::string(script) });
+      other_attributes.erase(attr_name);
     }
   };
 
@@ -752,6 +758,7 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
     AddCondition(config.post_conditions, toStr(post).c_str(), post);
   }
 
+  config.other_attributes = other_attributes;
   //---------------------------------------------
   TreeNode::Ptr new_node;
 
diff --git a/tests/gtest_ports.cpp b/tests/gtest_ports.cpp
index 8ba750919..69c351594 100644
--- a/tests/gtest_ports.cpp
+++ b/tests/gtest_ports.cpp
@@ -1,4 +1,5 @@
 #include <gtest/gtest.h>
+#include "behaviortree_cpp/basic_types.h"
 #include "behaviortree_cpp/bt_factory.h"
 #include "behaviortree_cpp/xml_parsing.h"
 #include "behaviortree_cpp/json_export.h"
@@ -129,6 +130,30 @@ TEST(PortTest, Descriptions)
   ASSERT_EQ(status, NodeStatus::FAILURE);  // failure because in_port_B="99"
 }
 
+TEST(PortsTest, NonPorts)
+{
+  std::string xml_txt =
+      R"(
+    <root BTCPP_format="4" >
+        <BehaviorTree ID="MainTree">
+            <Action ID="NodeWithPorts" name="NodeWithPortsName" in_port_B="66" _not_da_port="whateva" _skipIf="true" />
+        </BehaviorTree>
+    </root>)";
+
+  BehaviorTreeFactory factory;
+  factory.registerNodeType<NodeWithPorts>("NodeWithPorts");
+
+  auto tree = factory.createTreeFromText(xml_txt);
+
+  const TreeNode* root = tree.rootNode();
+  ASSERT_NE(root, nullptr);
+  ASSERT_EQ(root->type(), NodeType::ACTION);
+
+  EXPECT_EQ(root->config().other_attributes.size(), 1);
+  ASSERT_TRUE(root->config().other_attributes.contains("_not_da_port"));
+  EXPECT_EQ(root->config().other_attributes.at("_not_da_port"), "whateva");
+}
+
 struct MyType
 {
   std::string value;