diff --git a/gamedata/tf2.econ_data.txt b/gamedata/tf2.econ_data.txt
index 0ad7abc..410fec9 100644
--- a/gamedata/tf2.econ_data.txt
+++ b/gamedata/tf2.econ_data.txt
@@ -66,6 +66,11 @@
 				"linux"		"18"
 				"windows"	"18"
 			}
+			"CEconItemDefinition::m_AttributeList"
+			{
+				"linux"		"28"
+				"windows"	"28"
+			}
 			"CEconItemDefinition::m_pszLocalizedItemName"
 			{
 				// set near x-ref "Test Item %d"
diff --git a/scripting/include/tf_econ_data.inc b/scripting/include/tf_econ_data.inc
index 8cbeae6..c019900 100644
--- a/scripting/include/tf_econ_data.inc
+++ b/scripting/include/tf_econ_data.inc
@@ -50,6 +50,15 @@ native int TF2Econ_GetItemSlot(int defindex, TFClassType playerClass);
  */
 native bool TF2Econ_GetItemLevelRange(int defindex, int &iMinLevel, int &iMaxLevel);
 
+/**
+ * Returns an `ArrayList` containing attribute defindex / value pairs corresponding to the given
+ * item definition, or `null` if not a valid item definition.
+ * 
+ * This handle is owned by the calling plugin, so it should be `delete`d when not needed
+ * anymore.
+ */
+native ArrayList TF2Econ_GetItemStaticAttributes(int defindex);
+
 /**
  * Returns an arbiitrary string from an item definition's KeyValues structure.
  * You may use subkey notation ('/') to retrieve nested values.
@@ -105,6 +114,10 @@ native bool TF2Econ_IsAttributeHidden(int defindex);
 /** 
  * Returns true if the attribute is stored as an integer (corresponds to the "stored_as_integer"
  * key).
+ * 
+ * Not sure when this is actually used -- certain attributes such as
+ * "mod max primary clip override" are flagged as true, but are float values when retrieved
+ * via `TF2Econ_GetItemStaticAttributes()`.
  */
 native bool TF2Econ_IsAttributeStoredAsInteger(int defindex);
 
diff --git a/scripting/tf_econ_data.sp b/scripting/tf_econ_data.sp
index d2bb6da..3c3acfa 100644
--- a/scripting/tf_econ_data.sp
+++ b/scripting/tf_econ_data.sp
@@ -13,7 +13,7 @@
 #include <stocksoup/handles>
 #include <stocksoup/memory>
 
-#define PLUGIN_VERSION "0.8.1"
+#define PLUGIN_VERSION "0.9.0"
 public Plugin myinfo = {
 	name = "[TF2] Econ Data",
 	author = "nosoop",
@@ -45,6 +45,7 @@ public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int maxlen) {
 	CreateNative("TF2Econ_GetItemClassName", Native_GetItemClassName);
 	CreateNative("TF2Econ_GetItemSlot", Native_GetItemSlot);
 	CreateNative("TF2Econ_GetItemLevelRange", Native_GetItemLevelRange);
+	CreateNative("TF2Econ_GetItemStaticAttributes", Native_GetItemStaticAttributes);
 	CreateNative("TF2Econ_GetItemDefinitionString", Native_GetItemDefinitionString);
 	
 	// global items
@@ -130,6 +131,8 @@ public void OnPluginStart() {
 			GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_u8MinLevel");
 	offs_CEconItemDefinition_u8MaxLevel =
 			GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_u8MaxLevel");
+	offs_CEconItemDefinition_AttributeList =
+			GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_AttributeList");
 	offs_CEconItemDefinition_pszLocalizedItemName =
 			GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_pszLocalizedItemName");
 	offs_CEconItemDefinition_pszItemClassname =
diff --git a/scripting/tf_econ_data/item_definition.sp b/scripting/tf_econ_data/item_definition.sp
index f3566e0..0ac883e 100644
--- a/scripting/tf_econ_data/item_definition.sp
+++ b/scripting/tf_econ_data/item_definition.sp
@@ -1,6 +1,7 @@
 Address offs_CEconItemDefinition_pKeyValues,
 		offs_CEconItemDefinition_u8MinLevel,
 		offs_CEconItemDefinition_u8MaxLevel,
+		offs_CEconItemDefinition_AttributeList,
 		offs_CEconItemDefinition_pszLocalizedItemName,
 		offs_CEconItemDefinition_pszItemClassname,
 		offs_CEconItemDefinition_pszItemName;
@@ -92,6 +93,36 @@ bool GetItemLevelRange(int defindex, int &iMinLevel, int &iMaxLevel) {
 	return true;
 }
 
+public int Native_GetItemStaticAttributes(Handle hPlugin, int nParams) {
+	int defindex = GetNativeCell(1);
+	
+	Address pItemDef = GetEconItemDefinition(defindex);
+	if (!pItemDef) {
+		return view_as<int>(INVALID_HANDLE);
+	}
+	
+	// get size from CUtlVector
+	int nAttribs = LoadFromAddress(
+			pItemDef + offs_CEconItemDefinition_AttributeList + view_as<Address>(0x0C),
+			NumberType_Int32);
+	Address pAttribList = DereferencePointer(pItemDef + offs_CEconItemDefinition_AttributeList);
+	
+	// struct { attribute_defindex, value }
+	ArrayList attributeList = new ArrayList(2, nAttribs);
+	for (int i; i < nAttribs; i++) {
+		// TODO push attributes to list
+		Address pStaticAttrib = pAttribList + view_as<Address>(i * 0x08);
+		
+		int attrIndex = LoadFromAddress(pStaticAttrib, NumberType_Int16);
+		any attrValue = LoadFromAddress(pStaticAttrib + view_as<Address>(0x04),
+				NumberType_Int32);
+		
+		attributeList.Set(i, attrIndex, 0);
+		attributeList.Set(i, attrValue, 1);
+	}
+	return MoveHandle(attributeList, hPlugin);
+}
+
 public int Native_GetItemDefinitionString(Handle hPlugin, int nParams) {
 	int defindex = GetNativeCell(1);
 	int keylen;