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..d362146e3a
--- /dev/null
+++ b/meta/recipes-devtools/perl/files/CVE-2026-12087.patch
@@ -0,0 +1,161 @@
+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.42 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 | 84 ++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 57 insertions(+), 27 deletions(-)
+
+diff --git a/cpan/Socket/Socket.xs b/cpan/Socket/Socket.xs
+--- a/cpan/Socket/Socket.xs
++++ b/cpan/Socket/Socket.xs
+@@ -1272,26 +1272,35 @@
+         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");
+@@ -1331,33 +1340,48 @@
+         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 ", 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
+         PERL_UNUSED_VAR(multiaddr);
+@@ -1398,16 +1422,22 @@
+ #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.42.0.bb b/meta/recipes-devtools/perl/perl_5.42.0.bb
index 886eaaaa37..bbe979ab69 100644
--- a/meta/recipes-devtools/perl/perl_5.42.0.bb
+++ b/meta/recipes-devtools/perl/perl_5.42.0.bb
@@ -23,6 +23,7 @@ SRC_URI = "https://www.cpan.org/src/5.0/perl-${PV}.tar.gz;name=perl \
            file://CVE-2026-57432-02.patch \
            file://CVE-2026-42496.patch \
            file://CVE-2026-57433.patch \
+           file://CVE-2026-12087.patch \
            "
 SRC_URI:append:class-native = " \
            file://perl-configpm-switch.patch \
