diff --git a/mongoose.c b/mongoose.c
index 5d7d31b686bfb9ab9d8496fe3237591875af7f8f..e4491e8797d239edf0d245d4708191e8c7128f2c 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -1646,7 +1646,7 @@ static int url_decode(const char *src, int src_len, char *dst,
 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
 
   for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
-    if (src[i] == '%' &&
+    if (src[i] == '%' && i < src_len - 2 &&
         isxdigit(* (const unsigned char *) (src + i + 1)) &&
         isxdigit(* (const unsigned char *) (src + i + 2))) {
       a = tolower(* (const unsigned char *) (src + i + 1));
diff --git a/test/unit_test.c b/test/unit_test.c
index 1d9a9b7b78afd62f3422b9cdb3ed6b9c117d32e1..575cf37246264c81030406407b9f59d669bd52e9 100644
--- a/test/unit_test.c
+++ b/test/unit_test.c
@@ -583,10 +583,21 @@ static void test_url_decode(void) {
   ASSERT(url_decode("foo", 3, buf, 3, 0) == -1);  // No space for terminating \0
   ASSERT(url_decode("foo", 3, buf, 4, 0) == 3);
   ASSERT(strcmp(buf, "foo") == 0);
+
   ASSERT(url_decode("a+", 2, buf, sizeof(buf), 0) == 2);
   ASSERT(strcmp(buf, "a+") == 0);
+
   ASSERT(url_decode("a+", 2, buf, sizeof(buf), 1) == 2);
   ASSERT(strcmp(buf, "a ") == 0);
+
+  ASSERT(url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
+  ASSERT(strcmp(buf, "%") == 0);
+
+  ASSERT(url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
+  ASSERT(strcmp(buf, "%6") == 0);
+
+  ASSERT(url_decode("%61", 3, buf, sizeof(buf), 1) == 1);
+  ASSERT(strcmp(buf, "a") == 0);
 }
 
 static void test_mg_strcasestr(void) {