diff --git a/CHANGES b/CHANGES
index da458f6..95d21f1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+4934.	[security]	Simultaneous use of stale cache records and NSEC
+			aggressive negative caching could trigger a recursion
+			loop. (CVE-2018-5737) [GL #185]
+
 4914.	[security]	A bug in zone database reference counting could lead to
 			a crash when multiple versions of a slave zone were
 			transferred from a master in close succession.
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index b47202c..48b8515 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -4697,6 +4697,7 @@ check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header,
 		 */
 		if (KEEPSTALE(search->rbtdb) && stale > search->now) {
 			header->attributes |= RDATASET_ATTR_STALE;
+			*header_prev = header;
 			return ((search->options & DNS_DBFIND_STALEOK) == 0);
 		}
 
diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h
index a817364..537c6a4 100644
--- a/lib/ns/include/ns/query.h
+++ b/lib/ns/include/ns/query.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2017, 2018  Internet Systems Consortium, Inc. ("ISC")
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -31,6 +31,18 @@ typedef struct ns_dbversion {
 	ISC_LINK(struct ns_dbversion)	link;
 } ns_dbversion_t;
 
+/*%
+ * nameserver recursion parameters, to uniquely identify a recursion
+ * query; this is used to detect a recursion loop
+ */
+typedef struct ns_query_recparam {
+	dns_rdatatype_t			qtype;
+	dns_name_t *			qname;
+	dns_fixedname_t			fqname;
+	dns_name_t *			qdomain;
+	dns_fixedname_t			fqdomain;
+} ns_query_recparam_t;
+
 /*% nameserver query structure */
 struct ns_query {
 	unsigned int			attributes;
@@ -59,6 +71,7 @@ struct ns_query {
 	unsigned int			dns64_aaaaoklen;
 	unsigned int			dns64_options;
 	unsigned int			dns64_ttl;
+
 	struct {
 		dns_db_t *      	db;
 		dns_zone_t *      	zone;
@@ -72,6 +85,8 @@ struct ns_query {
 		isc_boolean_t		authoritative;
 		isc_boolean_t		is_zone;
 	} redirect;
+
+	ns_query_recparam_t		recparam;
 };
 
 #define NS_QUERYATTR_RECURSIONOK	0x0001
diff --git a/lib/ns/query.c b/lib/ns/query.c
index e4d5691..b7a003d 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -343,6 +343,10 @@ query_lookup(query_ctx_t *qctx);
 static void
 fetch_callback(isc_task_t *task, isc_event_t *event);
 
+static void
+recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
+		const dns_name_t *qname, const dns_name_t *qdomain);
+
 static isc_result_t
 query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
 	      dns_name_t *qdomain, dns_rdataset_t *nameservers,
@@ -697,6 +701,7 @@ query_reset(ns_client_t *client, isc_boolean_t everything) {
 	client->query.isreferral = ISC_FALSE;
 	client->query.dns64_options = 0;
 	client->query.dns64_ttl = ISC_UINT32_MAX;
+	recparam_update(&client->query.recparam, 0, NULL, NULL);
 }
 
 static void
@@ -5525,6 +5530,56 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
 }
 
 /*%
+ * Check whether the recursion parameters in 'param' match the current query's
+ * recursion parameters provided in 'qtype', 'qname', and 'qdomain'.
+ */
+static isc_boolean_t
+recparam_match(const ns_query_recparam_t *param, dns_rdatatype_t qtype,
+	       const dns_name_t *qname, const dns_name_t *qdomain)
+{
+	REQUIRE(param != NULL);
+
+	return (ISC_TF(param->qtype == qtype &&
+		       param->qname != NULL && qname != NULL &&
+		       param->qdomain != NULL && qdomain != NULL &&
+		       dns_name_equal(param->qname, qname) &&
+		       dns_name_equal(param->qdomain, qdomain)));
+}
+
+/*%
+ * Update 'param' with current query's recursion parameters provided in
+ * 'qtype', 'qname', and 'qdomain'.
+ */
+static void
+recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
+		const dns_name_t *qname, const dns_name_t *qdomain)
+{
+	isc_result_t result;
+
+	REQUIRE(param != NULL);
+
+	param->qtype = qtype;
+
+	if (qname == NULL) {
+		param->qname = NULL;
+	} else {
+		dns_fixedname_init(&param->fqname);
+		param->qname = dns_fixedname_name(&param->fqname);
+		result = dns_name_copy(qname, param->qname, NULL);
+		RUNTIME_CHECK(result == ISC_R_SUCCESS);
+	}
+
+	if (qdomain == NULL) {
+		param->qdomain = NULL;
+	} else {
+		dns_fixedname_init(&param->fqdomain);
+		param->qdomain = dns_fixedname_name(&param->fqdomain);
+		result = dns_name_copy(qdomain, param->qdomain, NULL);
+		RUNTIME_CHECK(result == ISC_R_SUCCESS);
+	}
+}
+
+/*%
  * Prepare client for recursion, then create a resolver fetch, with
  * the event callback set to fetch_callback(). Afterward we terminate
  * this phase of the query, and resume with a new query context when
@@ -5541,6 +5596,19 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
 
 	CTRACE(ISC_LOG_DEBUG(3), "query_recurse");
 
+	/*
+	 * Check recursion parameters from the previous query to see if they
+	 * match.  If not, update recursion parameters and proceed.
+	 */
+	if (recparam_match(&client->query.recparam, qtype, qname, qdomain)) {
+		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
+			      "recursion loop detected");
+		return (ISC_R_FAILURE);
+	}
+
+	recparam_update(&client->query.recparam, qtype, qname, qdomain);
+
 	if (!resuming)
 		inc_stats(client, ns_statscounter_recursion);
 
