diff --git a/meta/recipes-devtools/perl/files/CVE-2026-12087.patch b/meta/recipes-devtools/perl/files/CVE-2026-12087.patch
new file mode 100644
index 0000000000..535c9814d5
--- /dev/null
+++ b/meta/recipes-devtools/perl/files/CVE-2026-12087.patch
@@ -0,0 +1,165 @@
+From: Paul LeoNerd Evans <leonerd@leonerd.org.uk>
+Date: Mon, 4 May 2026 16:12:49 +0100
+Subject: cpan/Socket - Update to version 2.041
+
+2.041   2026-03-26
+        [CHANGES]
+         * Modernise Pod documentation formatting
+
+        [BUGFIXES]
+         * Fix reuse of `STRLEN len` variable in pack_ip_mreq_source()
+
+Backport changes:
+- Adjusted the upstream hunks to match the perl 5.38.4 code layout.
+- Drop not code files from the backport.
+
+CVE: CVE-2026-12087
+Upstream-Status: Backport [https://github.com/Perl/perl5/commit/de19a0b0ad1900fef976c5c1400bd8f11ec6c6cb]
+
+Signed-off-by: Jakub Szczudlo <jakub.szczudlo@nokia.com>
+---
+ cpan/Socket/Socket.xs | 87 +++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 56 insertions(+), 31 deletions(-)
+
+diff --git a/cpan/Socket/Socket.xs b/cpan/Socket/Socket.xs
+index b4bccb7..5fc558b 100644
+--- a/cpan/Socket/Socket.xs
++++ b/cpan/Socket/Socket.xs
+@@ -1270,28 +1270,36 @@ pack_ip_mreq(multiaddr, interface=&PL_sv_undef)
+ 	struct ip_mreq mreq;
+ 	char * multiaddrbytes;
+ 	char * interfacebytes;
+-	STRLEN len;
+-	if (DO_UTF8(multiaddr) && !sv_utf8_downgrade(multiaddr, 1))
+-		croak("Wide character in %s", "Socket::pack_ip_mreq");
+-	multiaddrbytes = SvPVbyte(multiaddr, len);
+-	if (len != sizeof(mreq.imr_multiaddr))
+-		croak("Bad arg length %s, length is %" UVuf
+-                      ", should be %" UVuf,
+-		      "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_multiaddr));
++
++        {
++            if (DO_UTF8(multiaddr) && !sv_utf8_downgrade(multiaddr, 1))
++                croak("Wide character in %s", "Socket::pack_ip_mreq");
++
++            STRLEN len;
++            multiaddrbytes = SvPVbyte(multiaddr, len);
++            if (len != sizeof(mreq.imr_multiaddr))
++                croak("Bad arg length %s, length is %" UVuf ", should be %" UVuf,
++                        "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_multiaddr));
++        }
++
+ 	Zero(&mreq, sizeof(mreq), char);
+ 	Copy(multiaddrbytes, &mreq.imr_multiaddr, sizeof(mreq.imr_multiaddr), char);
+ 	if(SvOK(interface)) {
+ 		if (DO_UTF8(interface) && !sv_utf8_downgrade(interface, 1))
+ 			croak("Wide character in %s", "Socket::pack_ip_mreq");
++
++            STRLEN len;
+ 		interfacebytes = SvPVbyte(interface, len);
+ 		if (len != sizeof(mreq.imr_interface))
+ 			croak("Bad arg length %s, length is %" UVuf
+                               ", should be %" UVuf,
+ 			      "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_interface));
++
+ 		Copy(interfacebytes, &mreq.imr_interface, sizeof(mreq.imr_interface), char);
+ 	}
+ 	else
+ 		mreq.imr_interface.s_addr = INADDR_ANY;
++
+ 	ST(0) = sv_2mortal(newSVpvn((char *)&mreq, sizeof(mreq)));
+ #else
+ 	not_here("pack_ip_mreq");
+@@ -1332,27 +1340,38 @@ pack_ip_mreq_source(multiaddr, source, interface=&PL_sv_undef)
+ 	char * multiaddrbytes;
+ 	char * sourcebytes;
+ 	char * interfacebytes;
+-	STRLEN len;
+-	if (DO_UTF8(multiaddr) && !sv_utf8_downgrade(multiaddr, 1))
+-		croak("Wide character in %s", "Socket::pack_ip_mreq_source");
+-	multiaddrbytes = SvPVbyte(multiaddr, len);
+-	if (len != sizeof(mreq.imr_multiaddr))
+-		croak("Bad arg length %s, length is %" UVuf
+-                      ", should be %" UVuf,
+-		      "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_multiaddr));
+-	if (DO_UTF8(source) && !sv_utf8_downgrade(source, 1))
+-		croak("Wide character in %s", "Socket::pack_ip_mreq_source");
+-	if (len != sizeof(mreq.imr_sourceaddr))
+-		croak("Bad arg length %s, length is %" UVuf
+-                      ", should be %" UVuf,
+-		      "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_sourceaddr));
+-	sourcebytes = SvPVbyte(source, len);
++
++        {
++            if (DO_UTF8(multiaddr) && !sv_utf8_downgrade(multiaddr, 1))
++                croak("Wide character in %s", "Socket::pack_ip_mreq_source");
++
++            STRLEN len;
++            multiaddrbytes = SvPVbyte(multiaddr, len);
++            if (len != sizeof(mreq.imr_multiaddr))
++                croak("Bad arg length %s, length is %" UVuf ", should be %" UVuf,
++                        "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_multiaddr));
++        }
++
++        {
++            if (DO_UTF8(source) && !sv_utf8_downgrade(source, 1))
++                croak("Wide character in %s", "Socket::pack_ip_mreq_source");
++
++            STRLEN len;
++            sourcebytes = SvPVbyte(source, len);
++            if (len != sizeof(mreq.imr_sourceaddr))
++                croak("Bad arg length %s, length is %" UVuf ", should be %" UVuf,
++                        "Socket::pack_ip_mreq", (UV)len, (UV)sizeof(mreq.imr_sourceaddr));
++        }
++
+ 	Zero(&mreq, sizeof(mreq), char);
+ 	Copy(multiaddrbytes, &mreq.imr_multiaddr, sizeof(mreq.imr_multiaddr), char);
+ 	Copy(sourcebytes, &mreq.imr_sourceaddr, sizeof(mreq.imr_sourceaddr), char);
++
+ 	if(SvOK(interface)) {
+ 		if (DO_UTF8(interface) && !sv_utf8_downgrade(interface, 1))
+ 			croak("Wide character in %s", "Socket::pack_ip_mreq");
++
++            STRLEN len;
+ 		interfacebytes = SvPVbyte(interface, len);
+ 		if (len != sizeof(mreq.imr_interface))
+ 			croak("Bad arg length %s, length is %" UVuf
+@@ -1362,6 +1381,7 @@ pack_ip_mreq_source(multiaddr, source, interface=&PL_sv_undef)
+ 	}
+ 	else
+ 		mreq.imr_interface.s_addr = INADDR_ANY;
++
+ 	ST(0) = sv_2mortal(newSVpvn((char *)&mreq, sizeof(mreq)));
+ #else
+ 	PERL_UNUSED_VAR(multiaddr);
+@@ -1403,17 +1423,22 @@ pack_ipv6_mreq(multiaddr, ifindex)
+ #ifdef HAS_IPV6_MREQ
+ 	struct ipv6_mreq mreq;
+ 	char * multiaddrbytes;
+-	STRLEN len;
+-	if (DO_UTF8(multiaddr) && !sv_utf8_downgrade(multiaddr, 1))
+-		croak("Wide character in %s", "Socket::pack_ipv6_mreq");
+-	multiaddrbytes = SvPVbyte(multiaddr, len);
+-	if (len != sizeof(mreq.ipv6mr_multiaddr))
+-		croak("Bad arg length %s, length is %" UVuf
+-                      ", should be %" UVuf,
+-		      "Socket::pack_ipv6_mreq", (UV)len, (UV)sizeof(mreq.ipv6mr_multiaddr));
++
++        {
++            if (DO_UTF8(multiaddr) && !sv_utf8_downgrade(multiaddr, 1))
++                croak("Wide character in %s", "Socket::pack_ipv6_mreq");
++
++            STRLEN len;
++            multiaddrbytes = SvPVbyte(multiaddr, len);
++            if (len != sizeof(mreq.ipv6mr_multiaddr))
++                croak("Bad arg length %s, length is %" UVuf ", should be %" UVuf,
++                        "Socket::pack_ipv6_mreq", (UV)len, (UV)sizeof(mreq.ipv6mr_multiaddr));
++        }
++
+ 	Zero(&mreq, sizeof(mreq), char);
+ 	Copy(multiaddrbytes, &mreq.ipv6mr_multiaddr, sizeof(mreq.ipv6mr_multiaddr), char);
+ 	mreq.ipv6mr_interface = ifindex;
++
+ 	ST(0) = sv_2mortal(newSVpvn((char *)&mreq, sizeof(mreq)));
+ #else
+ 	PERL_UNUSED_VAR(multiaddr);
diff --git a/meta/recipes-devtools/perl/perl_5.38.4.bb b/meta/recipes-devtools/perl/perl_5.38.4.bb
index 8ce5d3f5d0..df0f3ed0fb 100644
--- a/meta/recipes-devtools/perl/perl_5.38.4.bb
+++ b/meta/recipes-devtools/perl/perl_5.38.4.bb
@@ -25,6 +25,7 @@ SRC_URI = "https://www.cpan.org/src/5.0/perl-${PV}.tar.gz;name=perl \
            file://CVE-2026-57432-02.patch \
            file://CVE-2025-40909.patch \
            file://CVE-2026-19487.patch \
+           file://CVE-2026-12087.patch \
            "
 SRC_URI:append:class-native = " \
            file://perl-configpm-switch.patch \
