diff --git a/changelogs/unreleased/gh-9026-fix-heap-buffer-overflow.md b/changelogs/unreleased/gh-9026-fix-heap-buffer-overflow.md
new file mode 100644
index 0000000000000000000000000000000000000000..02e70fa305b077e7c4f862da8c30c6ffb9436021
--- /dev/null
+++ b/changelogs/unreleased/gh-9026-fix-heap-buffer-overflow.md
@@ -0,0 +1,3 @@
+## bugfix/core
+
+* Fixed a heap-buffer-overflow bug in fiber creation code (gh-9026).
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index 50ec73c7837d3505da2b45b1603c30336603612a..d66015c72c1be1807d0004eeff4e650bde2837cd 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -1189,12 +1189,13 @@ fiber_stack_recycle(struct fiber *fiber)
  * Initialize fiber stack watermark.
  */
 static void
-fiber_stack_watermark_create(struct fiber *fiber)
+fiber_stack_watermark_create(struct fiber *fiber,
+			     const struct fiber_attr *fiber_attr)
 {
 	assert(fiber->stack_watermark == NULL);
 
 	/* No tracking on custom stacks for simplicity. */
-	if (fiber->flags & FIBER_CUSTOM_STACK)
+	if (fiber_attr->flags & FIBER_CUSTOM_STACK)
 		return;
 
 	/*
@@ -1230,9 +1231,11 @@ fiber_stack_recycle(struct fiber *fiber)
 }
 
 static void
-fiber_stack_watermark_create(struct fiber *fiber)
+fiber_stack_watermark_create(struct fiber *fiber,
+			     const struct fiber_attr *fiber_attr)
 {
 	(void)fiber;
+	(void)fiber_attr;
 }
 #endif /* HAVE_MADV_DONTNEED */
 
@@ -1279,10 +1282,10 @@ fiber_stack_destroy(struct fiber *fiber, struct slab_cache *slabc)
 }
 
 static int
-fiber_stack_create(struct fiber *fiber, struct slab_cache *slabc,
-		   size_t stack_size)
+fiber_stack_create(struct fiber *fiber, const struct fiber_attr *fiber_attr,
+		   struct slab_cache *slabc)
 {
-	stack_size -= slab_sizeof();
+	size_t stack_size = fiber_attr->stack_size - slab_sizeof();
 	fiber->stack_slab = slab_get(slabc, stack_size);
 
 	if (fiber->stack_slab == NULL) {
@@ -1329,7 +1332,7 @@ fiber_stack_create(struct fiber *fiber, struct slab_cache *slabc,
 		return -1;
 	}
 
-	fiber_stack_watermark_create(fiber);
+	fiber_stack_watermark_create(fiber, fiber_attr);
 	return 0;
 }
 
@@ -1381,8 +1384,7 @@ fiber_new_ex(const char *name, const struct fiber_attr *fiber_attr,
 		fiber->storage.lua.storage_ref = FIBER_LUA_NOREF;
 		fiber->storage.lua.fid_ref = FIBER_LUA_NOREF;
 
-		if (fiber_stack_create(fiber, &cord()->slabc,
-				       fiber_attr->stack_size)) {
+		if (fiber_stack_create(fiber, fiber_attr, &cord()->slabc)) {
 			mempool_free(&cord->fiber_mempool, fiber);
 			return NULL;
 		}
diff --git a/test/unit/fiber_stack.c b/test/unit/fiber_stack.c
index 3c7cf881ce00e8e46f8d37c9345fc5879733b171..462540762c49f1244ae7e9d6fa1aced4c8fb2bd3 100644
--- a/test/unit/fiber_stack.c
+++ b/test/unit/fiber_stack.c
@@ -31,18 +31,41 @@ main_f(va_list ap)
 	struct errinj *inj;
 	struct fiber *fiber;
 	int fiber_count = fiber_count_total();
-	struct fiber_attr *fiber_attr = fiber_attr_new();
+	struct fiber_attr *fiber_attr;
 
 	header();
+#ifdef NDEBUG
+	plan(1);
+#else
 	plan(11);
+#endif
+
+	/*
+	 * gh-9026. Stack size crafted to be close to 64k so we should
+	 * hit red zone around stack when writing watermark if bug is not
+	 * fixed.
+	 *
+	 * The test is placed at the beginning because stderr is redirected
+	 * to /dev/null at the end of the test and ASAN diagnostic will
+	 * not be visible if the test will be placed at the end.
+	 */
+	fiber_attr = fiber_attr_new();
+	fiber_attr_setstacksize(fiber_attr, (64 << 10) - 128);
+	fiber = fiber_new_ex("gh-9026", fiber_attr, noop_f);
+	fiber_set_joinable(fiber, true);
+	fiber_start(fiber);
+	fiber_join(fiber);
+	fiber_attr_delete(fiber_attr);
 
 	/*
 	 * Check the default fiber stack size value.
 	 */
+	fiber_attr = fiber_attr_new();
 	ok(default_attr.stack_size == FIBER_STACK_SIZE_DEFAULT,
 	   "fiber_attr: the default stack size is %ld, but %d is set via CMake",
 	   default_attr.stack_size, FIBER_STACK_SIZE_DEFAULT);
 
+#ifndef NDEBUG
 	/*
 	 * Set non-default stack size to prevent reusing of an
 	 * existing fiber.
@@ -124,12 +147,13 @@ main_f(va_list ap)
 
 	cord_collect_garbage(cord());
 	ok(fiber_count_total() == fiber_count, "fiber is deleted");
+#endif /* ifndef NDEBUG */
 
 	fiber_attr_delete(fiber_attr);
-	footer();
-
 	ev_break(loop(), EVBREAK_ALL);
-	return check_plan();
+
+	footer();
+	return 0;
 }
 
 int main()
@@ -142,5 +166,5 @@ int main()
 	ev_run(loop(), 0);
 	fiber_free();
 	memory_free();
-	return 0;
+	return check_plan();
 }
diff --git a/test/unit/suite.ini b/test/unit/suite.ini
index d16ba413bcf4a041eecac2f6571abf3b1c69bfac..cc79666c39e903f9b01a50563e1997d83a5b5fa1 100644
--- a/test/unit/suite.ini
+++ b/test/unit/suite.ini
@@ -2,5 +2,5 @@
 core = unittest
 description = unit tests
 disabled = snap_quorum_delay.test
-release_disabled = fiber_stack.test swim_errinj.test
+release_disabled = swim_errinj.test
 is_parallel = True