diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index be54ed053bee7d6d3d918260251b3ccfaee14810..580e87954bbe7b79494294ed6471d54609102559 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -51,6 +51,7 @@
 
 // File constants
 static const int MAX_HDR_LEN = 20;
+static const S32 UNZIP_LLSD_MAX_DEPTH = 96;
 static const char LEGACY_NON_HEADER[] = "<llsd>";
 const std::string LLSD_BINARY_HEADER("LLSD/Binary");
 const std::string LLSD_XML_HEADER("LLSD/XML");
@@ -317,11 +318,11 @@ LLSDParser::LLSDParser()
 LLSDParser::~LLSDParser()
 { }
 
-S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes)
+S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes, S32 max_depth)
 {
 	mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true;
 	mMaxBytesLeft = max_bytes;
-	return doParse(istr, data);
+	return doParse(istr, data, max_depth);
 }
 
 
@@ -403,7 +404,7 @@ LLSDNotationParser::~LLSDNotationParser()
 { }
 
 // virtual
-S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
+S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
 {
 	// map: { string:object, string:object }
 	// array: [ object, object, object ]
@@ -418,6 +419,10 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
 	// binary: b##"ff3120ab1" | b(size)"raw data"
 	char c;
 	c = istr.peek();
+	if (max_depth == 0)
+	{
+		return PARSE_FAILURE;
+	}
 	while(isspace(c))
 	{
 		// pop the whitespace.
@@ -434,7 +439,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
 	{
 	case '{':
 	{
-		S32 child_count = parseMap(istr, data);
+		S32 child_count = parseMap(istr, data, max_depth - 1);
 		if((child_count == PARSE_FAILURE) || data.isUndefined())
 		{
 			parse_count = PARSE_FAILURE;
@@ -453,7 +458,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
 
 	case '[':
 	{
-		S32 child_count = parseArray(istr, data);
+		S32 child_count = parseArray(istr, data, max_depth - 1);
 		if((child_count == PARSE_FAILURE) || data.isUndefined())
 		{
 			parse_count = PARSE_FAILURE;
@@ -658,7 +663,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
 	return parse_count;
 }
 
-S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
+S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
 {
 	// map: { string:object, string:object }
 	map = LLSD::emptyMap();
@@ -693,7 +698,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
 				}
 				putback(istr, c);
 				LLSD child;
-				S32 count = doParse(istr, child);
+				S32 count = doParse(istr, child, max_depth);
 				if(count > 0)
 				{
 					// There must be a value for every key, thus
@@ -718,7 +723,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
 	return parse_count;
 }
 
-S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const
+S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
 {
 	// array: [ object, object, object ]
 	array = LLSD::emptyArray();
@@ -737,7 +742,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const
 				continue;
 			}
 			putback(istr, c);
-			S32 count = doParse(istr, child);
+			S32 count = doParse(istr, child, max_depth);
 			if(PARSE_FAILURE == count)
 			{
 				return PARSE_FAILURE;
@@ -869,7 +874,7 @@ LLSDBinaryParser::~LLSDBinaryParser()
 }
 
 // virtual
-S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
+S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
 {
 /**
  * Undefined: '!'<br>
@@ -893,12 +898,16 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
 	{
 		return 0;
 	}
+	if (max_depth == 0)
+	{
+		return PARSE_FAILURE;
+	}
 	S32 parse_count = 1;
 	switch(c)
 	{
 	case '{':
 	{
-		S32 child_count = parseMap(istr, data);
+		S32 child_count = parseMap(istr, data, max_depth - 1);
 		if((child_count == PARSE_FAILURE) || data.isUndefined())
 		{
 			parse_count = PARSE_FAILURE;
@@ -917,7 +926,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
 
 	case '[':
 	{
-		S32 child_count = parseArray(istr, data);
+		S32 child_count = parseArray(istr, data, max_depth - 1);
 		if((child_count == PARSE_FAILURE) || data.isUndefined())
 		{
 			parse_count = PARSE_FAILURE;
@@ -1098,7 +1107,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
 	return parse_count;
 }
 
-S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
+S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
 {
 	map = LLSD::emptyMap();
 	U32 value_nbo = 0;
@@ -1128,7 +1137,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
 		}
 		}
 		LLSD child;
-		S32 child_count = doParse(istr, child);
+		S32 child_count = doParse(istr, child, max_depth);
 		if(child_count > 0)
 		{
 			// There must be a value for every key, thus child_count
@@ -1152,7 +1161,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
 	return parse_count;
 }
 
-S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const
+S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
 {
 	array = LLSD::emptyArray();
 	U32 value_nbo = 0;
@@ -1168,7 +1177,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const
 	while((c != ']') && (count < size) && istr.good())
 	{
 		LLSD child;
-		S32 child_count = doParse(istr, child);
+		S32 child_count = doParse(istr, child, max_depth);
 		if(PARSE_FAILURE == child_count)
 		{
 			return PARSE_FAILURE;
@@ -2238,7 +2247,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 			return ZR_MEM_ERROR;
 		}
 
-		if (!LLSDSerialize::fromBinary(data, istr, cur_size))
+		if (!LLSDSerialize::fromBinary(data, istr, cur_size, UNZIP_LLSD_MAX_DEPTH))
 		{
 			free(result);
 			return ZR_PARSE_ERROR;
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 9f58d44fe7908b0fc70eb5eaba350a160feaea25..8165410e80d0c8d069a4c1c6d16dfcbb40b4d1f8 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -77,7 +77,7 @@ class LL_COMMON_API LLSDParser : public LLRefCount
 	 * @return Returns the number of LLSD objects parsed into
 	 * data. Returns PARSE_FAILURE (-1) on parse failure.
 	 */
-	S32 parse(std::istream& istr, LLSD& data, S32 max_bytes);
+	S32 parse(std::istream& istr, LLSD& data, S32 max_bytes, S32 max_depth = -1);
 
 	/** Like parse(), but uses a different call (istream.getline()) to read by lines
 	 *  This API is better suited for XML, where the parse cannot tell
@@ -103,10 +103,12 @@ class LL_COMMON_API LLSDParser : public LLRefCount
 	 * caller.
 	 * @param istr The input stream.
 	 * @param data[out] The newly parse structured data.
+	 * @param max_depth Max depth parser will check before exiting
+	 *  with parse error, -1 - unlimited.
 	 * @return Returns the number of LLSD objects parsed into
 	 * data. Returns PARSE_FAILURE (-1) on parse failure.
 	 */
-	virtual S32 doParse(std::istream& istr, LLSD& data) const = 0;
+	virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const = 0;
 
 	/** 
 	 * @brief Virtual default function for resetting the parser
@@ -241,10 +243,12 @@ class LL_COMMON_API LLSDNotationParser : public LLSDParser
 	 * caller.
 	 * @param istr The input stream.
 	 * @param data[out] The newly parse structured data. Undefined on failure.
+	 * @param max_depth Max depth parser will check before exiting
+	 *  with parse error, -1 - unlimited.
 	 * @return Returns the number of LLSD objects parsed into
 	 * data. Returns PARSE_FAILURE (-1) on parse failure.
 	 */
-	virtual S32 doParse(std::istream& istr, LLSD& data) const;
+	virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const;
 
 private:
 	/** 
@@ -252,18 +256,20 @@ class LL_COMMON_API LLSDNotationParser : public LLSDParser
 	 *
 	 * @param istr The input stream.
 	 * @param map The map to add the parsed data.
+	 * @param max_depth Allowed parsing depth.
 	 * @return Returns The number of LLSD objects parsed into data.
 	 */
-	S32 parseMap(std::istream& istr, LLSD& map) const;
+	S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const;
 
 	/** 
 	 * @brief Parse an array from the istream.
 	 *
 	 * @param istr The input stream.
 	 * @param array The array to append the parsed data.
+	 * @param max_depth Allowed parsing depth.
 	 * @return Returns The number of LLSD objects parsed into data.
 	 */
-	S32 parseArray(std::istream& istr, LLSD& array) const;
+	S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const;
 
 	/** 
 	 * @brief Parse a string from the istream and assign it to data.
@@ -314,10 +320,12 @@ class LL_COMMON_API LLSDXMLParser : public LLSDParser
 	 * caller.
 	 * @param istr The input stream.
 	 * @param data[out] The newly parse structured data.
+	 * @param max_depth Max depth parser will check before exiting
+	 *  with parse error, -1 - unlimited.
 	 * @return Returns the number of LLSD objects parsed into
 	 * data. Returns PARSE_FAILURE (-1) on parse failure.
 	 */
-	virtual S32 doParse(std::istream& istr, LLSD& data) const;
+	virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const;
 
 	/** 
 	 * @brief Virtual default function for resetting the parser
@@ -362,10 +370,12 @@ class LL_COMMON_API LLSDBinaryParser : public LLSDParser
 	 * caller.
 	 * @param istr The input stream.
 	 * @param data[out] The newly parse structured data.
+	 * @param max_depth Max depth parser will check before exiting
+	 *  with parse error, -1 - unlimited.
 	 * @return Returns the number of LLSD objects parsed into
 	 * data. Returns -1 on parse failure.
 	 */
-	virtual S32 doParse(std::istream& istr, LLSD& data) const;
+	virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const;
 
 private:
 	/** 
@@ -373,18 +383,20 @@ class LL_COMMON_API LLSDBinaryParser : public LLSDParser
 	 *
 	 * @param istr The input stream.
 	 * @param map The map to add the parsed data.
+	 * @param max_depth Allowed parsing depth.
 	 * @return Returns The number of LLSD objects parsed into data.
 	 */
-	S32 parseMap(std::istream& istr, LLSD& map) const;
+	S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const;
 
 	/** 
 	 * @brief Parse an array from the istream.
 	 *
 	 * @param istr The input stream.
 	 * @param array The array to append the parsed data.
+	 * @param max_depth Allowed parsing depth.
 	 * @return Returns The number of LLSD objects parsed into data.
 	 */
-	S32 parseArray(std::istream& istr, LLSD& array) const;
+	S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const;
 
 	/** 
 	 * @brief Parse a string from the istream and assign it to data.
@@ -800,16 +812,16 @@ class LL_COMMON_API LLSDSerialize
 		LLPointer<LLSDBinaryFormatter> f = new LLSDBinaryFormatter;
 		return f->format(sd, str, LLSDFormatter::OPTIONS_NONE);
 	}
-	static S32 fromBinary(LLSD& sd, std::istream& str, S32 max_bytes)
+	static S32 fromBinary(LLSD& sd, std::istream& str, S32 max_bytes, S32 max_depth = -1)
 	{
 		LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser;
-		return p->parse(str, sd, max_bytes);
+		return p->parse(str, sd, max_bytes, max_depth);
 	}
-	static LLSD fromBinary(std::istream& str, S32 max_bytes)
+	static LLSD fromBinary(std::istream& str, S32 max_bytes, S32 max_depth = -1)
 	{
 		LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser;
 		LLSD sd;
-		(void)p->parse(str, sd, max_bytes);
+		(void)p->parse(str, sd, max_bytes, max_depth);
 		return sd;
 	}
 };
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 8d72a1c329e176d1d38d24f2824c14195f27533f..6d0fe862b9189f8a0a41887a50f12cf54272d865 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -917,7 +917,7 @@ void LLSDXMLParser::parsePart(const char *buf, int len)
 }
 
 // virtual
-S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const
+S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
 {
 	#ifdef XML_PARSER_PERFORMANCE_TESTS
 	XML_Timer timer( &parseTime );