new file mode 100644
@@ -0,0 +1,90 @@
+From ff034061b24642e15340b0696e5c9a0aa8410fab Mon Sep 17 00:00:00 2001
+From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
+Date: Wed, 22 Jul 2026 10:17:32 +0200
+Subject: [PATCH] - Fix CVE-2026-55717, 'serve-expired-client-timeout' and
+ 'response-ip' CNAME redirect could lead to a crash. Thanks to Qifan Zhang,
+ Palo Alto Networks, for the report. In addition, thanks to Xin Wang,
+ Jiapeng Li, and Jiajia Liu, Northwestern Polytechnical University, for also
+ reporting this issue.
+
+(cherry picked from commit 2ce2ca36912644d2dbf97249a41494a9e2500fc3)
+
+CVE: CVE-2026-55717
+Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/2ce2ca36912644d2dbf97249a41494a9e2500fc3]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ services/localzone.h | 2 +-
+ services/mesh.c | 15 ++++++++++-----
+ util/data/packed_rrset.c | 1 +
+ 3 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/services/localzone.h b/services/localzone.h
+index 66102fd98..9ec57e2a1 100644
+--- a/services/localzone.h
++++ b/services/localzone.h
+@@ -565,7 +565,7 @@ enum respip_action {
+ respip_always_nxdomain = local_zone_always_nxdomain,
+ /** answer with nodata response */
+ respip_always_nodata = local_zone_always_nodata,
+- /** answer with nodata response */
++ /** drop query */
+ respip_always_deny = local_zone_always_deny,
+ /** RPZ: truncate answer in order to force switch to tcp */
+ respip_truncate = local_zone_truncate,
+diff --git a/services/mesh.c b/services/mesh.c
+index 6a04bc838..191b1d488 100644
+--- a/services/mesh.c
++++ b/services/mesh.c
+@@ -2391,9 +2391,10 @@ apply_respip_action(struct module_qstate* qstate,
+
+ /* xxx_deny actions mean dropping the reply, unless the original reply
+ * was redirected to response-ip data. */
+- if((actinfo->action == respip_deny ||
++ if(actinfo->action == respip_always_deny ||
++ ((actinfo->action == respip_deny ||
+ actinfo->action == respip_inform_deny) &&
+- *encode_repp == rep)
++ *encode_repp == rep))
+ *encode_repp = NULL;
+
+ return 1;
+@@ -2458,12 +2459,15 @@ mesh_serve_expired_callback(void* arg)
+ qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
+ qstate->env->auth_zones)) {
+ return;
+- } else if(partial_rep &&
+- !respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
++ } else if(partial_rep) {
++ if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
+ qstate->client_info, must_validate, &encode_rep, qstate->region,
+ qstate->env->auth_zones, qstate->env->views,
+ qstate->env->respip_set)) {
+- return;
++ return;
++ }
++ /* merge succeeded; final reply, no further alias pass */
++ partial_rep = NULL;
+ }
+ if(!encode_rep || alias_rrset) {
+ if(!encode_rep) {
+@@ -2474,6 +2478,7 @@ mesh_serve_expired_callback(void* arg)
+ partial_rep = encode_rep;
+ }
+ }
++ msg->rep = encode_rep;
+ /* We've found a partial reply ending with an
+ * alias. Replace the lookup qinfo for the
+ * alias target and lookup the cache again to
+diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c
+index d18486cc5..720c56ac3 100644
+--- a/util/data/packed_rrset.c
++++ b/util/data/packed_rrset.c
+@@ -198,6 +198,7 @@ get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
+ {
+ struct packed_rrset_data* d;
+ size_t len;
++ if(!rrset) return;
+ if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
+ ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
+ return;
@@ -37,6 +37,7 @@ SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=master;t
file://CVE-2026-52863.patch \
file://CVE-2026-54478.patch \
file://CVE-2026-55708.patch \
+ file://CVE-2026-55717.patch \
"
SRCREV = "f6269baa605d31859f28770e01a24e3677e5f82c"