diff --git a/lib/cookies/helper.c b/lib/cookies/helper.c
index 6f8616170031f9029b0d0ca0e366c7577a8a9891..019b863dd40aaf241dbf001f8d01bd751c98c531 100644
--- a/lib/cookies/helper.c
+++ b/lib/cookies/helper.c
@@ -46,9 +46,9 @@ static const uint8_t *peek_and_check_cc(kr_cookie_lru_t *cache, const void *sa,
 }
 
 /**
- * @brief Add a client cookie option into the RR Set.
+ * @brief Put a client cookie into the RR Set.
  */
-static int opt_rr_add_cookie(knot_rrset_t *opt_rr, uint8_t *data,
+static int opt_rr_put_cookie(knot_rrset_t *opt_rr, uint8_t *data,
                              uint16_t data_len, knot_mm_t *mm)
 {
 	assert(opt_rr && data && data_len > 0);
@@ -84,9 +84,9 @@ static int opt_rr_add_cookie(knot_rrset_t *opt_rr, uint8_t *data,
 }
 
 /**
- * @brief Adds entire EDNS option into the RR Set.
+ * @brief Puts entire EDNS option into the RR Set.
  */
-static int opt_rr_add_cookie_opt(knot_rrset_t *opt_rr, uint8_t *option, knot_mm_t *mm)
+static int opt_rr_put_cookie_opt(knot_rrset_t *opt_rr, uint8_t *option, knot_mm_t *mm)
 {
 	assert(opt_rr && option);
 
@@ -99,20 +99,20 @@ static int opt_rr_add_cookie_opt(knot_rrset_t *opt_rr, uint8_t *option, knot_mm_
 	uint16_t opt_len = knot_edns_opt_get_length(option);
 	uint8_t *opt_data = knot_edns_opt_get_data(option);
 
-	return opt_rr_add_cookie(opt_rr, opt_data, opt_len, mm);
+	return opt_rr_put_cookie(opt_rr, opt_data, opt_len, mm);
 }
 
 int kr_request_put_cookie(const struct kr_cookie_comp *clnt_comp,
                           kr_cookie_lru_t *cookie_cache,
                           const struct sockaddr *clnt_sa,
                           const struct sockaddr *srvr_sa,
-                          knot_pkt_t *pkt)
+                          struct kr_request *req)
 {
-	if (!clnt_comp || !pkt) {
+	if (!clnt_comp || !req) {
 		return kr_error(EINVAL);
 	}
 
-	if (!pkt->opt_rr) {
+	if (!req->ctx->opt_rr) {
 		return kr_ok();
 	}
 
@@ -120,8 +120,10 @@ int kr_request_put_cookie(const struct kr_cookie_comp *clnt_comp,
 		return kr_error(EINVAL);
 	}
 
-	/* Generate client cookie from client address, server address and
-	 * secret quantity. */
+	/*
+	 * Generate client cookie from client address, server address and
+	 * secret quantity.
+	 */
 	struct knot_cc_input input = {
 		.clnt_sockaddr = clnt_sa,
 		.srvr_sockaddr = srvr_sa,
@@ -141,25 +143,18 @@ int kr_request_put_cookie(const struct kr_cookie_comp *clnt_comp,
 	const uint8_t *cached_cookie = peek_and_check_cc(cookie_cache,
 	                                                 srvr_sa, cc, cc_len);
 
-	/* This is a very nasty hack that prevents the packet to be corrupted
-	 * when using contemporary 'Cookie interface'. */
-	assert(pkt->current == KNOT_ADDITIONAL);
-	pkt->sections[KNOT_ADDITIONAL].count -= 1;
-	pkt->rrset_count -= 1;
-	pkt->size -= knot_edns_wire_size(pkt->opt_rr);
-	knot_wire_set_arcount(pkt->wire, knot_wire_get_arcount(pkt->wire) - 1);
-
+	/* Add cookie option. */
 	int ret;
 	if (cached_cookie) {
-		ret = opt_rr_add_cookie_opt(pkt->opt_rr,
+		ret = opt_rr_put_cookie_opt(req->ctx->opt_rr,
 		                            (uint8_t *)cached_cookie,
-		                            &pkt->mm);
+		                            req->ctx->pool);
 	} else {
-		ret = opt_rr_add_cookie(pkt->opt_rr, cc, cc_len, &pkt->mm);
+		ret = opt_rr_put_cookie(req->ctx->opt_rr, cc, cc_len,
+		                        req->ctx->pool);
 	}
 
-	/* Write to packet. */
-	return knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
+	return ret;
 }
 
 int kr_answer_write_cookie(const struct knot_sc_private *srvr_data,
diff --git a/lib/cookies/helper.h b/lib/cookies/helper.h
index 8ceee2029050782dfa1027c6449448fe4ac6107f..b876c8048fd039720ea8325f6fb49d28dc4ee5e6 100644
--- a/lib/cookies/helper.h
+++ b/lib/cookies/helper.h
@@ -23,15 +23,16 @@
 #include "lib/cookies/lru_cache.h"
 #include "lib/cookies/nonce.h"
 #include "lib/defines.h"
+#include "lib/resolve.h"
 
 /**
- * @brief Insert a DNS cookie into query packet.
- * @note The packet must already contain ENDS section.
+ * @brief Updates DNS cookie in the request EDNS options.
+ * @note This function must be called before the request packet is finalised.
  * @param clnt_comp    client cookie control structure
  * @param cookie_cache cookie cache
  * @param clnt_sa      client socket address
  * @param srvr_sa      server socket address
- * @param pkt          DNS request packet
+ * @param req          name resolution request
  * @return kr_ok() or error code
  */
 KR_EXPORT
@@ -39,7 +40,7 @@ int kr_request_put_cookie(const struct kr_cookie_comp *clnt_comp,
                           kr_cookie_lru_t *cookie_cache,
                           const struct sockaddr *clnt_sa,
                           const struct sockaddr *srvr_sa,
-                          knot_pkt_t *pkt);
+                          struct kr_request *req);
 
 /**
  * @brief Inserts a cookie option into the OPT RR. It does not write any
diff --git a/lib/resolve.c b/lib/resolve.c
index 2e910f943fc4ad33cf25f85d2d564c5081a7cdfc..9d5a1da40d868d6283e0d54d77233d001b40cb5e 100644
--- a/lib/resolve.c
+++ b/lib/resolve.c
@@ -857,12 +857,10 @@ ns_election:
 
 #if defined(ENABLE_COOKIES)
 /** Update DNS cookie data in packet. */
-static bool outbound_query_add_cookies(struct kr_request *req,
-                                       const struct sockaddr *dst,
-                                       knot_pkt_t *pkt)
+static bool outbound_request_update_cookies(struct kr_request *req,
+                                            const struct sockaddr *dst)
 {
 	assert(req);
-	assert(pkt);
 
 	/* RFC7873 4.1 strongly requires server address. */
 	if (!dst) {
@@ -872,7 +870,7 @@ static bool outbound_query_add_cookies(struct kr_request *req,
 	struct kr_cookie_settings *clnt_sett = &req->ctx->cookie_ctx.clnt;
 
 	/* Cookies disabled or packet has no ENDS section. */
-	if (!clnt_sett->enabled || !pkt->opt_rr) {
+	if (!clnt_sett->enabled) {
 		return true;
 	}
 
@@ -890,7 +888,7 @@ static bool outbound_query_add_cookies(struct kr_request *req,
 	 */
 
 	kr_request_put_cookie(&clnt_sett->current, req->ctx->cache_cookie,
-	                      NULL, dst, pkt);
+	                      NULL, dst, req);
 
 	return true;
 }
@@ -919,13 +917,8 @@ int kr_resolve_query_finalize(struct kr_request *request, struct sockaddr *dst,
 	 * cons: Additional stress on API before sending every packet.
 	 */
 
-	int ret = query_finalize(request, qry, packet);
-	if (ret != 0) {
-		return KNOT_STATE_FAIL;
-	}
-
 #if defined(ENABLE_COOKIES)
-	/* Update DNS cookies data in query. */
+	/* Update DNS cookies in request. */
 	if (type == SOCK_DGRAM) { /* @todo: Add cookies also over TCP? */
 		/* The actual server IP address is needed before generating the
 		 * actual cookie. If we don't know the server address then we
@@ -933,12 +926,17 @@ int kr_resolve_query_finalize(struct kr_request *request, struct sockaddr *dst,
 		 * Also the resolver somehow mangles the query packets before
 		 * building the query i.e. the space needed for the cookie
 		 * cannot be allocated in the cookie layer. */
-		if (!outbound_query_add_cookies(request, dst, packet)) {
+		if (!outbound_request_update_cookies(request, dst)) {
 			return KNOT_STATE_FAIL;
 		}
 	}
 #endif /* defined(ENABLE_COOKIES) */
 
+	int ret = query_finalize(request, qry, packet);
+	if (ret != 0) {
+		return KNOT_STATE_FAIL;
+	}
+
 	WITH_DEBUG {
 	char qname_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[INET6_ADDRSTRLEN], type_str[16];
 	knot_dname_to_str(qname_str, knot_pkt_qname(packet), sizeof(qname_str));