new file mode 100644
@@ -0,0 +1,160 @@
+From 839620179e2b4e5982c53d8956d92e690d82960c Mon Sep 17 00:00:00 2001
+From: Eduardo Silva <eduardo@chronosphere.io>
+Date: Thu, 9 Apr 2026 12:11:52 -0600
+Subject: [PATCH] server: http: fix malformed request crash paths
+
+Fix the reproducible malformed-request crash paths in the HTTP
+request lifecycle.
+
+Handle missing Host data in directory redirects, reject malformed
+range delimiters before substring parsing, and avoid reusing invalid
+request state while advancing pipelined requests.
+
+Verified by rebuilding with cmake --build build and replaying the
+reported crash-inducing request fixtures against build/bin/monkey.
+
+Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
+
+This patch is part of https://github.com/monkey/monkey/pull/434,
+containing assorted CVE fixes.
+
+Upstream-Status: Backport [https://github.com/monkey/monkey/commit/1570f41231888ae8c7fbd719704e2486a952e45d]
+Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
+---
+ mk_core/mk_memory.c | 10 ++++++++++
+ mk_server/mk_http.c | 46 +++++++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 52 insertions(+), 4 deletions(-)
+
+diff --git a/mk_core/mk_memory.c b/mk_core/mk_memory.c
+index c4073e23..008f7ac6 100644
+--- a/mk_core/mk_memory.c
++++ b/mk_core/mk_memory.c
+@@ -52,6 +52,16 @@ char *mk_ptr_to_buf(mk_ptr_t p)
+ {
+ char *buf;
+
++ if (!p.data || p.len == 0) {
++ buf = mk_mem_alloc(1);
++ if (!buf) {
++ return NULL;
++ }
++
++ buf[0] = '\0';
++ return buf;
++ }
++
+ buf = mk_mem_alloc(p.len + 1);
+ if (!buf) return NULL;
+
+diff --git a/mk_server/mk_http.c b/mk_server/mk_http.c
+index ad12a74a..f2f12554 100644
+--- a/mk_server/mk_http.c
++++ b/mk_server/mk_http.c
+@@ -457,6 +457,10 @@ static int mk_http_range_parse(struct mk_http_request *sr)
+ if ((sep_pos = mk_string_char_search(sr->range.data, '-', sr->range.len)) < 0)
+ return -1;
+
++ if (sep_pos < eq_pos) {
++ return -1;
++ }
++
+ len = sr->range.len;
+ sh = &sr->headers;
+
+@@ -476,10 +480,16 @@ static int mk_http_range_parse(struct mk_http_request *sr)
+ /* =yyy-xxx */
+ if ((eq_pos + 1 != sep_pos) && (len > sep_pos + 1)) {
+ buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, sep_pos);
++ if (!buffer) {
++ return -1;
++ }
+ sh->ranges[0] = (unsigned long) atol(buffer);
+ mk_mem_free(buffer);
+
+ buffer = mk_string_copy_substr(sr->range.data, sep_pos + 1, len);
++ if (!buffer) {
++ return -1;
++ }
+ sh->ranges[1] = (unsigned long) atol(buffer);
+ mk_mem_free(buffer);
+
+@@ -493,6 +503,9 @@ static int mk_http_range_parse(struct mk_http_request *sr)
+ /* =yyy- */
+ if ((eq_pos + 1 != sep_pos) && (len == sep_pos + 1)) {
+ buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, len);
++ if (!buffer) {
++ return -1;
++ }
+ sr->headers.ranges[0] = (unsigned long) atol(buffer);
+ mk_mem_free(buffer);
+
+@@ -522,7 +535,16 @@ static int mk_http_directory_redirect_check(struct mk_http_session *cs,
+ return 0;
+ }
+
++ if (!sr->host.data || sr->host.len <= 0) {
++ mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server);
++ return -1;
++ }
++
+ host = mk_ptr_to_buf(sr->host);
++ if (!host) {
++ mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server);
++ return -1;
++ }
+
+ /*
+ * Add ending slash to the location string
+@@ -588,6 +610,9 @@ static inline char *mk_http_index_lookup(mk_ptr_t *path_base,
+ }
+
+ off = path_base->len;
++ if ((size_t) off >= buf_size) {
++ return NULL;
++ }
+ memcpy(buf, path_base->data, off);
+
+ mk_list_foreach(head, server->index_files) {
+@@ -1138,15 +1163,27 @@ int mk_http_request_end(struct mk_http_session *cs, struct mk_server *server)
+ ret = mk_http_parser_more(&cs->parser, cs->body_length);
+ if (ret == MK_TRUE) {
+ /* Our pipeline request limit is the same that our keepalive limit */
++ if (cs->parser.i < 0 ||
++ (unsigned int) (cs->parser.i + 1) >= cs->body_length) {
++ goto shutdown;
++ }
++
+ cs->counter_connections++;
+ len = (cs->body_length - cs->parser.i) -1;
++ if (len <= 0) {
++ goto shutdown;
++ }
+ memmove(cs->body,
+ cs->body + cs->parser.i + 1,
+ len);
+ cs->body_length = len;
+
+ /* Prepare for next one */
+- sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head);
++ if (mk_list_is_empty(&cs->request_list) == 0) {
++ cs->close_now = MK_TRUE;
++ goto shutdown;
++ }
++ sr = &cs->sr_fixed;
+ mk_http_request_free(sr, server);
+ mk_http_request_init(cs, sr, server);
+ mk_http_parser_init(&cs->parser);
+@@ -1626,9 +1663,10 @@ int mk_http_sched_done(struct mk_sched_conn *conn,
+ struct mk_http_request *sr;
+
+ session = mk_http_session_get(conn);
+- sr = mk_list_entry_first(&session->request_list,
+- struct mk_http_request, _head);
+- mk_plugin_stage_run_40(session, sr, server);
++ if (mk_list_is_empty(&session->request_list) != 0) {
++ sr = &session->sr_fixed;
++ mk_plugin_stage_run_40(session, sr, server);
++ }
+
+ return mk_http_request_end(session, server);
+ }
new file mode 100644
@@ -0,0 +1,51 @@
+From 82fb537e74e9b801d196b76efaf735ee50cd86c6 Mon Sep 17 00:00:00 2001
+From: Eduardo Silva <eduardo@chronosphere.io>
+Date: Thu, 9 Apr 2026 12:43:31 -0600
+Subject: [PATCH] server: scheduler: guard protocol close callback
+
+Avoid calling a null cb_close handler from the scheduler close
+and timeout paths.
+
+This fixes the HTTP/2 upgrade case where the protocol handler can be
+switched to mk_http2_handler even though that handler does not
+implement cb_close.
+
+Verified by rebuilding with cmake --build build.
+
+Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
+
+This patch is part of https://github.com/monkey/monkey/pull/434,
+containing assorted CVE fixes.
+
+Upstream-Status: Backport [https://github.com/monkey/monkey/commit/fc1d68fb38044df08cb43c7d9af0f68714388efc]
+Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
+---
+ mk_server/mk_scheduler.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/mk_server/mk_scheduler.c b/mk_server/mk_scheduler.c
+index a680d3cd..3cf0ba40 100644
+--- a/mk_server/mk_scheduler.c
++++ b/mk_server/mk_scheduler.c
+@@ -598,8 +598,10 @@ int mk_sched_check_timeouts(struct mk_sched_worker *sched,
+ MK_TRACE("Scheduler, closing fd %i due TIMEOUT",
+ conn->event.fd);
+ MK_LT_SCHED(conn->event.fd, "TIMEOUT_CONN_PENDING");
+- conn->protocol->cb_close(conn, sched, MK_SCHED_CONN_TIMEOUT,
+- server);
++ if (conn->protocol->cb_close) {
++ conn->protocol->cb_close(conn, sched, MK_SCHED_CONN_TIMEOUT,
++ server);
++ }
+ mk_sched_drop_connection(conn, sched, server);
+ }
+ }
+@@ -749,7 +751,7 @@ int mk_sched_event_close(struct mk_sched_conn *conn,
+ MK_TRACE("[FD %i] Connection Handler, closed", conn->event.fd);
+ mk_event_del(sched->loop, &conn->event);
+
+- if (type != MK_EP_SOCKET_DONE) {
++ if (type != MK_EP_SOCKET_DONE && conn->protocol->cb_close) {
+ conn->protocol->cb_close(conn, sched, type, server);
+ }
+ /*
new file mode 100644
@@ -0,0 +1,108 @@
+From b9f24a2968fa62de4a6ecf070fa0389ce10e7729 Mon Sep 17 00:00:00 2001
+From: Eduardo Silva <eduardo@chronosphere.io>
+Date: Thu, 9 Apr 2026 12:11:57 -0600
+Subject: [PATCH] server: parser: harden boundary checks
+
+Tighten parser and helper validation around explicit lengths and
+buffer boundaries.
+
+Require exact header literal matches, validate chunk length tokens,
+and guard helper routines that previously trusted inconsistent
+pointer or length state.
+
+Verified by rebuilding with cmake --build build and replaying the
+reported malformed request fixtures against build/bin/monkey.
+
+Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
+
+This patch is part of https://github.com/monkey/monkey/pull/434,
+containing assorted CVE fixes.
+
+Upstream-Status: Backport [https://github.com/monkey/monkey/commit/ffe0d0ed1b074ea6f3965c37bb754e9f19130a82]
+Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
+---
+ include/monkey/mk_http_parser.h | 6 +++++-
+ mk_server/mk_http_parser.c | 13 +++++++++++++
+ mk_server/mk_mimetype.c | 7 ++++++-
+ mk_server/mk_user.c | 2 +-
+ 4 files changed, 25 insertions(+), 3 deletions(-)
+
+diff --git a/include/monkey/mk_http_parser.h b/include/monkey/mk_http_parser.h
+index 9e3b365e..465ea0e4 100644
+--- a/include/monkey/mk_http_parser.h
++++ b/include/monkey/mk_http_parser.h
+@@ -389,7 +389,11 @@ int mk_http_parser_chunked_decode_buf(struct mk_http_parser *p,
+
+ static inline int mk_http_parser_more(struct mk_http_parser *p, int len)
+ {
+- if (abs(len - p->i) - 1 > 0) {
++ if (len <= 0 || p->i < 0) {
++ return MK_FALSE;
++ }
++
++ if ((p->i + 1) < len) {
+ return MK_TRUE;
+ }
+
+diff --git a/mk_server/mk_http_parser.c b/mk_server/mk_http_parser.c
+index 9413528a..3c831f29 100644
+--- a/mk_server/mk_http_parser.c
++++ b/mk_server/mk_http_parser.c
+@@ -173,6 +173,16 @@ static inline void request_set(mk_ptr_t *ptr, struct mk_http_parser *p, char *bu
+ static inline int header_cmp(const char *expected, char *value, int len)
+ {
+ int i = 0;
++ size_t expected_len;
++
++ if (len < 0) {
++ return -1;
++ }
++
++ expected_len = strlen(expected);
++ if ((size_t) len != expected_len) {
++ return -1;
++ }
+
+ if (len >= 8) {
+ if (expected[0] != tolower(value[0])) return -1;
+@@ -535,6 +545,9 @@ parse_more:
+ (errno != 0)) {
+ return MK_HTTP_PARSER_ERROR;
+ }
++ if (ptr == tmp || *ptr != '\0') {
++ return MK_HTTP_PARSER_ERROR;
++ }
+
+ if (chunk_len < 0) {
+ return MK_HTTP_PARSER_ERROR;
+diff --git a/mk_server/mk_mimetype.c b/mk_server/mk_mimetype.c
+index b86b4ef1..5462ea5c 100644
+--- a/mk_server/mk_mimetype.c
++++ b/mk_server/mk_mimetype.c
+@@ -197,7 +197,12 @@ struct mk_mimetype *mk_mimetype_find(struct mk_server *server, mk_ptr_t *filenam
+ {
+ int j, len;
+
+- j = len = filename->len;
++ if (!filename->data || filename->len <= 0) {
++ return NULL;
++ }
++
++ len = filename->len;
++ j = len - 1;
+
+ /* looking for extension */
+ while (j >= 0 && filename->data[j] != '.') {
+diff --git a/mk_server/mk_user.c b/mk_server/mk_user.c
+index 7200ff08..716331ac 100644
+--- a/mk_server/mk_user.c
++++ b/mk_server/mk_user.c
+@@ -46,7 +46,7 @@ int mk_user_init(struct mk_http_session *cs, struct mk_http_request *sr,
+ }
+
+ limit = mk_string_char_search(sr->uri_processed.data + offset, '/',
+- sr->uri_processed.len);
++ sr->uri_processed.len - offset);
+
+ if (limit == -1) {
+ limit = (sr->uri_processed.len) - offset;
@@ -11,7 +11,11 @@ SRC_URI = "git://github.com/monkey/monkey;branch=master;protocol=https \
file://0001-fastcgi-Use-value-instead-of-address-of-sin6_port.patch \
file://0001-include-Fix-location-of-mk_core.h-etal.patch \
file://monkey.service \
- file://monkey.init"
+ file://monkey.init \
+ file://0001-server-http-fix-malformed-request-crash-paths.patch \
+ file://0002-server-scheduler-guard-protocol-close-callback.patch \
+ file://0003-server-parser-harden-boundary-checks.patch \
+ "
SRCREV = "94af273244369e1a8426d0d1f6376475aff90db9"