diff --git a/src/cmdu.c b/src/cmdu.c
index 3fdbfa2708e491f836f4145e2ca767563839b150..c01d7de7488d4e094bc74eba69d6fb4e12b54895 100644
--- a/src/cmdu.c
+++ b/src/cmdu.c
@@ -575,7 +575,7 @@ int cmdu_parse_tlv_single(struct cmdu_buff *c, struct tlv *tv[],
 	int len;
 
 
-	if (!c)
+	if (!c || !c->data || !c->datalen)
 		return -1;
 
 	if (*num == 0)
@@ -598,7 +598,7 @@ int cmdu_parse_tlv_single(struct cmdu_buff *c, struct tlv *tv[],
 			continue;
 
 		if (tv[0] && policy->present == TLV_PRESENT_ONE)
-			break;
+			return -1;
 
 		if (i >= *num)
 			break;
@@ -606,6 +606,14 @@ int cmdu_parse_tlv_single(struct cmdu_buff *c, struct tlv *tv[],
 		tv[i++] = t;
 	}
 
+	/* malformed cmdu if data remaining */
+	if (len)
+		return -1;
+
+	/* exactly one tlv must be present */
+	if (policy->present == TLV_PRESENT_ONE && !tv[0])
+		return -1;
+
 	*num = i;
 	return 0;
 }
@@ -619,7 +627,7 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 	int i;
 
 
-	if (!c)
+	if (!c || !c->data || !c->datalen)
 		return -1;
 
 	for (i = 0; i < policy_len; i++) {
@@ -646,13 +654,23 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 
 			if (tv[i][0]) {
 				if (policy[i].present == TLV_PRESENT_ONE)
-					continue;
+					return -1;
 			}
 
 			tv[i][idx[i]++] = t;
 		}
 	}
 
+	/* malformed cmdu if data remaining */
+	if (len)
+		return -1;
+
+	/* strictly check against tlv policies */
+	for (i = 0; i < policy_len; i++) {
+		if (policy[i].present == TLV_PRESENT_ONE && !tv[i][0])
+			return -1;
+	}
+
 	return 0;
 }