diff --git a/meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch b/meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch
new file mode 100644
index 00000000000..c5aec0802c9
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch
@@ -0,0 +1,128 @@
+From f247c0a2fb5b3e48a771d2d23efc9a45c64e957d Mon Sep 17 00:00:00 2001
+From: Sachin Monga <smonga@linux.ibm.com>
+Date: Thu, 1 Oct 2026 00:51:23 +0530
+Subject: [PATCH] powerpc: Fix one byte overread in strncasecmp (bug 34683,
+ CVE-2026-97399)
+
+The Power8 strncasecmp (strcasecmp.S with USE_AS_STRNCASECMP) touches
+s1[n]/s2[n] in three places when the first n bytes compare equal and
+contain no NUL: L(loop) preloads the next byte before its bdnz;
+L(loop1) increments then loads before its bdnz; and L(bytebybyte) loads
+s1[0]/s2[0] before checking r5. A caller that maps exactly n readable bytes
+can get SIGSEGV if byte n falls on an unmapped page.
+
+The L(bytebybyte) site was identified by Florian Weimer; the
+original AISLE report covered only the two loops.
+
+Fix all three sites: guard L(bytebybyte) with a r5 == 0 check, split the
+bdnz/load pairs in L(loop) and L(loop1) so the load only runs when the
+count is still positive, and preload rCHAR1/rCHAR2 in L(lessthan4) after
+confirming r5 != 0.  strcasecmp is unaffected; its generated code is
+unchanged.
+
+Add string/test-strncasecmp-nonarray.c, built on the test-Xncmp-nonarray.c
+skeleton: maps a PROT_NONE page past both buffers and sweeps all start
+offsets and lengths.  Runs as an xtest.
+
+Reported-by: AISLE in partnership with Red Hat
+Suggested-by: Florian Weimer <fweimer@redhat.com>
+(cherry picked from commit e622f82ea8797704ac8f761f88ed3e429e97fedd)
+
+CVE: CVE-2026-97399
+Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=f247c0a2fb5b3e48a771d2d23efc9a45c64e957d]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ string/Makefile                               |  4 +--
+ string/test-strncasecmp-nonarray.c            |  4 +++
+ sysdeps/powerpc/powerpc64/power8/strcasecmp.S | 25 +++++++++++++++----
+ 3 files changed, 26 insertions(+), 7 deletions(-)
+ create mode 100644 string/test-strncasecmp-nonarray.c
+
+diff --git a/string/Makefile b/string/Makefile
+index c83b195e2e..d7437cd915 100644
+--- a/string/Makefile
++++ b/string/Makefile
+@@ -238,8 +238,8 @@ endif
+ # This test allocates a lot of memory and can run for a long time.
+ xtests += tst-strcoll-overflow
+ 
+-# This test runs for a long time.
+-xtests += test-strncmp-nonarray
++# These tests run for a long time.
++xtests += test-strncasecmp-nonarray test-strncmp-nonarray
+ 
+ # This test needs libdl.
+ ifeq (yes,$(build-shared))
+diff --git a/string/test-strncasecmp-nonarray.c b/string/test-strncasecmp-nonarray.c
+new file mode 100644
+index 0000000000..d68e58d5ec
+--- /dev/null
++++ b/string/test-strncasecmp-nonarray.c
+@@ -0,0 +1,4 @@
++#define TEST_IDENTIFIER strncasecmp
++#define TEST_NAME "strncasecmp"
++typedef char CHAR;
++#include "test-Xncmp-nonarray.c"
+diff --git a/sysdeps/powerpc/powerpc64/power8/strcasecmp.S b/sysdeps/powerpc/powerpc64/power8/strcasecmp.S
+index 7ce53407b8..838b8bf75f 100644
+--- a/sysdeps/powerpc/powerpc64/power8/strcasecmp.S
++++ b/sysdeps/powerpc/powerpc64/power8/strcasecmp.S
+@@ -355,6 +355,14 @@ L(bytebybyte):
+ 	offset and string descriptors are only updated in the end
+ 	of loop unrolling. */
+ 	ld	rLOC, LOCALE_CTYPE_TOLOWER(rLOC)
++#ifdef USE_AS_STRNCASECMP
++	/* This entry point can be reached from the vector loop with
++	   r5 == 0 (the last vector chunk ended exactly at the `n'
++	   boundary).  Do not read s1[0]/s2[0] in that case: those
++	   bytes are s1[n]/s2[n], one past the caller's bound.  */
++	cmpdi	cr7, r5, 0
++	beq	cr7, L(retnull)
++#endif
+ 	lbz	rCHAR1, 0(rSTR1)	/* Load char from s1 */
+ 	lbz	rCHAR2, 0(rSTR2)	/* Load char from s2 */
+ #ifdef USE_AS_STRNCASECMP
+@@ -405,19 +413,23 @@ L(loop):
+ 	cmpw	cr1, rLWR1, rLWR2
+ 	crorc	4*cr1+eq,eq,4*cr1+eq
+ 	beq     cr1, L(done)
++#ifdef USE_AS_STRNCASECMP
++	/* Test the remaining count before touching the next byte. */
++	bdnz	L(loop_load)
++	b	L(lessthan4)
++L(loop_load):
++#endif
+ 	lbz	rCHAR1, 0(rSTR1)	/* Load char from s1 */
+ 	lbz	rCHAR2, 0(rSTR2)	/* Load char from s2 */
+-#ifdef USE_AS_STRNCASECMP
+-	bdnz	L(loop)
+-#else
+ 	b	L(loop)
+-#endif
+ #ifdef USE_AS_STRNCASECMP
+ L(lessthan4):
+ 	clrldi	r5, r5, 62
+ 	cmpdi	cr7, r5, 0
+ 	beq	cr7, L(retnull)
+ 	mtctr	r5
++	lbz	rCHAR1, 0(rSTR1)
++	lbz	rCHAR2, 0(rSTR2)
+ L(loop1):
+ 	cmpdi	rCHAR1, 0
+ 	sldi	rADDR1, rCHAR1, 2
+@@ -427,11 +439,14 @@ L(loop1):
+ 	cmpw	cr1, rLWR1, rLWR2
+ 	crorc	4*cr1+eq,eq,4*cr1+eq
+ 	beq	cr1, L(done)
++	bdnz	L(loop1_load)
++	b	L(retnull)
++L(loop1_load):
+ 	addi	rSTR1, rSTR1, 1
+ 	addi	rSTR2, rSTR2, 1
+ 	lbz	rCHAR1, 0(rSTR1)
+ 	lbz	rCHAR2, 0(rSTR2)
+-	bdnz	L(loop1)
++	b	L(loop1)
+ #endif
+ L(done):
+ 	subf	r0, rLWR2, rLWR1
diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb
index 66250fbdb2a..3e377f66875 100644
--- a/meta/recipes-core/glibc/glibc_2.39.bb
+++ b/meta/recipes-core/glibc/glibc_2.39.bb
@@ -80,6 +80,7 @@ SRC_URI =  "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \
            file://0045-CVE-2026-86805-CVE-2026-95818-03.patch \
            file://0046-CVE-2026-86805-CVE-2026-95818-04.patch \
            file://0047-CVE-2026-89092.patch \
+           file://0048-CVE-2026-97399.patch \
 "
 S = "${WORKDIR}/git"
 B = "${WORKDIR}/build-${TARGET_SYS}"
