diff --git a/meta/recipes-connectivity/libpcap/libpcap/02-CVE-2026-31912.patch b/meta/recipes-connectivity/libpcap/libpcap/02-CVE-2026-31912.patch
new file mode 100644
index 0000000000..f32c5ed39e
--- /dev/null
+++ b/meta/recipes-connectivity/libpcap/libpcap/02-CVE-2026-31912.patch
@@ -0,0 +1,630 @@
+From 09e04074ddfbca5fa33693c6e2d4f01a74857f65 Mon Sep 17 00:00:00 2001
+From: Denis Ovsienko <denis@ovsienko.info>
+Date: Thu, 30 Jul 2026 13:33:55 +0100
+Subject: [PATCH] CVE-2026-31912: Mind the program bounds in
+ pcap_offline_filter().
+
+The current revision of pcapint_filter_with_aux_data() does not know the
+number of instructions in the filter program, it assumes the program
+counter always remains within the bounds of the provided filter program
+and always reaches a return instruction.  This holds for programs that
+have been generated or validated by libpcap.
+
+However, this does not necessarily hold for programs that come from an
+external source via pcap_offline_filter() or [deprecated] bpf_filter()
+and have not been explicitly validated.  If the interpreter executes
+such a program and advances the program counter beyond the last
+instruction, it will be interpreting memory space after the filter
+program as BPF instructions, which in the current implementation will
+eventually cause either abort() (another commit addresses that) or
+SIGSEGV.
+
+To fix the latter problem, in pcapint_filter_with_aux_data() add a
+parameter for the number of instructions in the program and reject the
+packet as soon as (or just before) the program counter goes out of
+bounds.  Update all incoming code paths to specify the length; also in
+pcap_offline_filter(3PCAP) make it clear the function now requires the
+'bf_len' member to be set correctly and uses it.
+
+(backported from commit d1209988c74dd9330659898d3b676ee6bbe1c551)
+
+(cherry picked from commit d3f358d3cffbe1ecb94d5284b3e81f052a0adcb9)
+
+Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/d3f358d3cffbe1ecb94d5284b3e81f052a0adcb9]
+CVE: CVE-2026-31912
+
+Notes on backporting to 1.10.6:
+ - Adjusted the pcapint_filter() call sites in pcap-dag.c, pcap-netmap.c and
+   pcap-snf.c to the 1.10.6 code base.  In 1.10.7 these were already touched by
+   the unrelated "low snaplen" fixes (commits d5192db3, fb87fdeb, b0caefe8),
+   which are not part of this CVE and are not backported here; only the new
+   bf_len argument is added to each call.
+ - In bpf_filter.c the scratch-memory-store zero-initialisation and the removal
+   of the stray BPF_S_ANC_* enum (1.10.7-only cleanups) are not present in
+   1.10.6, so only the new pc0 declaration and bounds checks from this commit
+   are added.
+
+Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
+---
+ CHANGES                  | 1 +
+ bpf_filter.c              | 137 +++++++++++++++++++++++++++++++-------
+ dlpisubs.c                |   3 +-
+ pcap-bpf.c                |   3 +-
+ pcap-bt-linux.c           |   3 +-
+ pcap-bt-monitor-linux.c   |   3 +-
+ pcap-dag.c                |   4 +-
+ pcap-dbus.c               |   3 +-
+ pcap-dpdk.c               |   4 +-
+ pcap-haiku.c              |   4 +-
+ pcap-int.h                |   8 ++-
+ pcap-linux.c              |   1 +
+ pcap-netfilter-linux.c    |   4 +-
+ pcap-netmap.c             |   3 +-
+ pcap-npf.c                |   3 +-
+ pcap-rdmasniff.c          |   3 +-
+ pcap-snf.c                |   3 +-
+ pcap-usb-linux.c          |   8 +--
+ pcap.c                    |   2 +-
+ pcap_offline_filter.3pcap |  27 +++++++-
+ savefile.c                |   3 +-
+ 21 files changed, 182 insertions(+), 48 deletions(-)
+diff --git a/CHANGES b/CHANGES
+index 74f8ddf..ab812dd 100644
+--- a/CHANGES
++++ b/CHANGES
+@@ -1,6 +1,7 @@
+ 1.10.6 + backported CVE fixes / The Tcpdump Group
+   Backported security fixes:
+     CVE-2026-0799: Access M[] safely in the BPF interpreter.
++    CVE-2026-31912: Mind the program bounds in pcap_offline_filter().
+ 
+ Tuesday, December 30, 2025 / The Tcpdump Group
+   Summary for 1.10.6 libpcap release
+diff --git a/bpf_filter.c b/bpf_filter.c
+index 510dbd9c..4f9adeea 100644
+--- a/bpf_filter.c
++++ b/bpf_filter.c
+@@ -70,6 +70,24 @@ enum {
+         BPF_S_ANC_VLAN_TAG_PRESENT,
+ };
+ 
++/*
++ * Kernel BPF implementations tend to define BPF_MAXINSNS to 512 or 4096, the
++ * userland interpreter in libpcap is meant to support much longer filter
++ * programs.  In the latter case it is important that BPF_MAXINSNS does not
++ * interfere with the safety checks in the validator and the interpreter:
++ *   (BPF_MAXINSNS + UINT8_MAX) * sizeof(struct bpf_insn) < UINT32_MAX
++ * It makes the most sense to be able to interpret as many instructions as
++ * pcap_compile() can produce, without optimization, for a valid filter
++ * expression before it consumes as much memory as the current definitions of
++ * NCHUNKS and CHUNKSIZE() allow.  For some expressions this can be almost
++ * 1.53 million instructions on a 64-bit machine and twice as many on a 32-bit
++ * machine.
++ */
++#ifdef BPF_MAXINSNS
++#undef BPF_MAXINSNS
++#endif
++#define BPF_MAXINSNS 3060000U
++
+ /*
+  * Execute the filter program starting at pc on the packet p
+  * wirelen is the length of the original packet
+@@ -84,12 +102,14 @@ enum {
+  */
+ #if defined(SKF_AD_VLAN_TAG_PRESENT)
+ u_int
+-pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+-    u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data)
++pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_int proglen,
++    const u_char *p, const u_int wirelen, const u_int buflen,
++    const struct pcap_bpf_aux_data *aux_data)
+ #else
+ u_int
+-pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+-    u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data _U_)
++pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_int proglen,
++    const u_char *p, const u_int wirelen, const u_int buflen,
++    const struct pcap_bpf_aux_data *aux_data _U_)
+ #endif
+ {
+ 	register uint32_t A, X;
+@@ -99,13 +119,36 @@ pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+ 	if (pc == 0)
+ 		/*
+ 		 * No filter means accept all.
++		 * In this case the value of 'proglen' is irrelevant.
+ 		 */
+ 		return (u_int)-1;
++	if (proglen < 1 || proglen > BPF_MAXINSNS)
++		return 0;
++
++	/*
++	 * Require the current instruction pointer not to overflow for both the
++	 * filter program (where the pointer will be dereferenced) and an
++	 * immediately following margin (where it will be not).  So long as the
++	 * margin is large enough to represent the destination of any single
++	 * conditional [forward] jump from within the filter program, a single
++	 * guard prevents all filter program over-read attempts that result
++	 * from the program running out of instructions before a BPF_RET or a
++	 * conditional jump directing the interpreter beyond the program end.
++	 * Unconditional jumps mean a larger problem space, which the BPF_JA
++	 * case below addresses separately.
++	 */
++	const struct bpf_insn *pcend = pc + proglen;
++	if (pcend + UINT8_MAX < pc)
++		return 0;
++
+ 	A = 0;
+ 	X = 0;
++	const struct bpf_insn *pc0 = pc;
+ 	--pc;
+ 	for (;;) {
+ 		++pc;
++		if (pc >= pcend)
++			return 0;
+ 		switch (pc->code) {
+ 
+ 		default:
+@@ -241,6 +284,40 @@ DIAG_ON_DEFAULT_ONLY_SWITCH
+ 			continue;
+ 
+ 		case BPF_JMP|BPF_JA:
++			/*
++			 * The pointer (pc) decrements and increments in units
++			 * of sizeof(struct bpf_insn) == 8 bytes.  The number
++			 * of units is in the [INT32_MIN, INT32_MAX] interval,
++			 * hence the result can point before the beginning or
++			 * beyond the end of the filter program and can under-
++			 * or overflow; also on 32-bit architectures it can
++			 * under- or overflow more than once and can test
++			 * negative for underflow, overflow and out-of-range
++			 * conditions after under- or overflowing at least
++			 * once.
++			 *
++			 * However, it has been verified above that the program
++			 * length is sufficiently small and the pointer does
++			 * not wrap within the bounds of the filter program, so
++			 * there is a one-to-one correspondence between BPF
++			 * program counter values [0, proglen) and all valid
++			 * values of the pointer.  In other words, after this
++			 * unconditional jump the pointer arithmetic result
++			 * will be valid iff BPF program counter value will be
++			 * valid.  For the latter problem the solution is
++			 * almost the same as in the validator.
++			 *
++			 * The main difference is that here the current value
++			 * of BPF program counter is not a 32-bit unsigned
++			 * variable, but a ptrdiff_t expression, which is
++			 * 64-bit signed on 64-bit architectures and 32-bit
++			 * signed on 32-bit architectures.  However, the cast
++			 * to 32-bit unsigned is safe in both cases because:
++			 * pc0 <= pc < pc0 + proglen, therefore:
++			 * 0 <= pc - pc0 < proglen <= BPF_MAXINSNS < INT32_MAX
++			 */
++			if ((bpf_u_int32)(pc - pc0) + 1 + pc->k >= proglen)
++				return 0;
+ 			/*
+ 			 * XXX - we currently implement "ip6 protochain"
+ 			 * with backward jumps, so sign-extend pc->k.
+@@ -394,10 +471,10 @@ DIAG_ON_DEFAULT_ONLY_SWITCH
+ }
+ 
+ u_int
+-pcapint_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+-    u_int buflen)
++pcapint_filter(const struct bpf_insn *pc, const u_int proglen, const u_char *p,
++    u_int wirelen, u_int buflen)
+ {
+-	return pcapint_filter_with_aux_data(pc, p, wirelen, buflen, NULL);
++	return pcapint_filter_with_aux_data(pc, proglen, p, wirelen, buflen, NULL);
+ }
+ 
+ /*
+@@ -417,7 +494,7 @@ pcapint_validate_filter(const struct bpf_insn *f, int len)
+ 	u_int i, from;
+ 	const struct bpf_insn *p;
+ 
+-	if (len < 1)
++	if (len < 1 || (u_int)len > BPF_MAXINSNS || f + len < f)
+ 		return 0;
+ 
+ 	for (i = 0; i < (u_int)len; ++i) {
+@@ -483,33 +560,45 @@ pcapint_validate_filter(const struct bpf_insn *f, int len)
+ 		case BPF_JMP:
+ 			/*
+ 			 * Check that jumps are within the code block,
+-			 * and that unconditional branches don't go
+-			 * backwards as a result of an overflow.
++			 * regardless of the direction.  libpcap uses
++			 * backward jumps to implement the "protochain"
++			 * primitive.  All offsets that mean a backward
++			 * jump in libpcap (whether in-range or not) in
++			 * kernel BPF implementations mean out-of-range
++			 * or overflow forward jumps -- kernel
++			 * implementations must reject that.
++			 *
+ 			 * Unconditional branches have a 32-bit offset,
+ 			 * so they could overflow; we check to make
+ 			 * sure they don't.  Conditional branches have
+ 			 * an 8-bit offset, and the from address is <=
+-			 * BPF_MAXINSNS, and we assume that BPF_MAXINSNS
++			 * BPF_MAXINSNS, and we know that BPF_MAXINSNS
+ 			 * is sufficiently small that adding 255 to it
+ 			 * won't overflow.
+ 			 *
+ 			 * We know that len is <= BPF_MAXINSNS, and we
+-			 * assume that BPF_MAXINSNS is < the maximum size
++			 * know that BPF_MAXINSNS is < the maximum value
+ 			 * of a u_int, so that i + 1 doesn't overflow.
+-			 *
+-			 * For userland, we don't know that the from
+-			 * or len are <= BPF_MAXINSNS, but we know that
+-			 * from <= len, and, except on a 64-bit system,
+-			 * it's unlikely that len, if it truly reflects
+-			 * the size of the program we've been handed,
+-			 * will be anywhere near the maximum size of
+-			 * a u_int.  We also don't check for backward
+-			 * branches, as we currently support them in
+-			 * userland for the protochain operation.
+ 			 */
+ 			from = i + 1;
+ 			switch (BPF_OP(p->code)) {
+ 			case BPF_JA:
++				/*
++				 * So long as both 'from' and bpf_insn.k are
++				 * 32-bit unsigned, this check rejects any jump
++				 * offset that points outside of the valid BPF
++				 * address space of the filter program no
++				 * matter whether signed interpretation of the
++				 * offset is positive or negative.
++				 *
++				 * Note that this condition is necessary, but
++				 * not sufficient to get correct results from
++				 * respective pointer arithmetic in the process
++				 * address space.  Other necessary conditions
++				 * are that BPF_MAXINSNS is correctly defined
++				 * and enforced, and that the pointer does not
++				 * overflow.
++				 */
+ 				if (from + p->k >= (u_int)len)
+ 					return 0;
+ 				break;
+@@ -537,12 +626,14 @@ pcapint_validate_filter(const struct bpf_insn *f, int len)
+ 
+ /*
+  * Exported because older versions of libpcap exported them.
++ * This function is deprecated and unsafe, use pcap_offline_filter() instead.
+  */
+ u_int
+ bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+     u_int buflen)
+ {
+-	return pcapint_filter(pc, p, wirelen, buflen);
++	// The actual length of the filter program is not known.
++	return pcapint_filter(pc, BPF_MAXINSNS, p, wirelen, buflen);
+ }
+ 
+ int
+diff --git a/dlpisubs.c b/dlpisubs.c
+index d4310de5..19934059 100644
+--- a/dlpisubs.c
++++ b/dlpisubs.c
+@@ -203,7 +203,8 @@ pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user,
+ 		bufp += caplen;
+ #endif
+ 		++pd->stat.ps_recv;
+-		if (pcapint_filter(p->fcode.bf_insns, pk, origlen, caplen)) {
++		if (pcapint_filter(p->fcode.bf_insns, p->fcode.bf_len,
++		                   pk, origlen, caplen)) {
+ #ifdef HAVE_SYS_BUFMOD_H
+ 			pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec;
+ 			pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;
+diff --git a/pcap-bpf.c b/pcap-bpf.c
+index 49bb273d..13f83930 100644
+--- a/pcap-bpf.c
++++ b/pcap-bpf.c
+@@ -1372,7 +1372,8 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+ #endif
+ 		 */
+ 		if (pb->filtering_in_kernel ||
+-		    pcapint_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
++		    pcapint_filter(p->fcode.bf_insns, p->fcode.bf_len,
++		                   datap, bhp->bh_datalen, caplen)) {
+ 			struct pcap_pkthdr pkthdr;
+ #ifdef BIOCSTSTAMP
+ 			struct bintime bt;
+diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c
+index 2fc51665..9f464e70 100644
+--- a/pcap-bt-linux.c
++++ b/pcap-bt-linux.c
+@@ -396,7 +396,8 @@ DIAG_ON_SIGN_COMPARE
+ 	pkth.caplen+=sizeof(pcap_bluetooth_h4_header);
+ 	pkth.len = pkth.caplen;
+ 	if (handle->fcode.bf_insns == NULL ||
+-	    pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
++	    pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++	                   pktd, pkth.len, pkth.caplen)) {
+ 		callback(user, &pkth, pktd);
+ 		return 1;
+ 	}
+diff --git a/pcap-bt-monitor-linux.c b/pcap-bt-monitor-linux.c
+index dfba8051..cfe52498 100644
+--- a/pcap-bt-monitor-linux.c
++++ b/pcap-bt-monitor-linux.c
+@@ -153,7 +153,8 @@ DIAG_ON_SIGN_COMPARE
+     bthdr->opcode = htons(hdr.opcode);
+ 
+     if (handle->fcode.bf_insns == NULL ||
+-        pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
++        pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++                       pktd, pkth.len, pkth.caplen)) {
+         callback(user, &pkth, pktd);
+         return 1;
+     }
+diff --git a/pcap-dag.c b/pcap-dag.c
+index 5ce15dd5..334a970c 100644
+--- a/pcap-dag.c
++++ b/pcap-dag.c
+@@ -666,7 +666,9 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+ 			caplen = p->snapshot;
+ 
+ 		/* Run the packet filter if there is one. */
+-		if ((p->fcode.bf_insns == NULL) || pcapint_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
++		if ((p->fcode.bf_insns == NULL) ||
++		    pcapint_filter(p->fcode.bf_insns, p->fcode.bf_len,
++		                   dp, packet_len, caplen)) {
+ 
+ 			/* convert between timestamp formats */
+ 			register unsigned long long ts;
+diff --git a/pcap-dbus.c b/pcap-dbus.c
+index d29fb81d..b0f30f6f 100644
+--- a/pcap-dbus.c
++++ b/pcap-dbus.c
+@@ -90,7 +90,8 @@ dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *us
+ 
+ 		gettimeofday(&pkth.ts, NULL);
+ 		if (handle->fcode.bf_insns == NULL ||
+-		    pcapint_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
++		    pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++		                   (u_char *)raw_msg, pkth.len, pkth.caplen)) {
+ 			handlep->packets_read++;
+ 			callback(user, &pkth, (u_char *)raw_msg);
+ 			count++;
+diff --git a/pcap-dpdk.c b/pcap-dpdk.c
+index c78724e5..4fb8ffea 100644
+--- a/pcap-dpdk.c
++++ b/pcap-dpdk.c
+@@ -405,7 +405,9 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
+ 
+ 			}
+ 			if (bp){
+-				if (p->fcode.bf_insns==NULL || pcapint_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){
++				if (p->fcode.bf_insns==NULL ||
++				    pcapint_filter(p->fcode.bf_insns, p->fcode.bf_len,
++				                   bp, pcap_header.len, pcap_header.caplen)){
+ 					cb(cb_arg, &pcap_header, bp);
+ 				}else{
+ 					pd->bpf_drop++;
+diff --git a/pcap-haiku.c b/pcap-haiku.c
+index 609f585a..7b994fee 100644
+--- a/pcap-haiku.c
++++ b/pcap-haiku.c
+@@ -112,8 +112,8 @@ pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback,
+ 	if (handle->fcode.bf_insns) {
+ 		// NB: pcapint_filter() takes the wire length and the captured
+ 		// length, not the snapshot length of the pcap_t handle.
+-		if (pcapint_filter(handle->fcode.bf_insns, buffer, wireLength,
+-		                   captureLength) == 0)
++		if (pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++		                   buffer, wireLength, captureLength) == 0)
+ 			goto drop;
+ 	}
+ 
+diff --git a/pcap-int.h b/pcap-int.h
+index ce0ac698..3d466946 100644
+--- a/pcap-int.h
++++ b/pcap-int.h
+@@ -579,13 +579,15 @@ struct pcap_bpf_aux_data {
+  * Filtering routine that takes the auxiliary data as an additional
+  * argument.
+  */
+-u_int	pcapint_filter_with_aux_data(const struct bpf_insn *,
+-    const u_char *, u_int, u_int, const struct pcap_bpf_aux_data *);
++u_int	pcapint_filter_with_aux_data(const struct bpf_insn *, const u_int,
++    const u_char *, const u_int, const u_int,
++    const struct pcap_bpf_aux_data *);
+ 
+ /*
+  * Filtering routine that doesn't.
+  */
+-u_int	pcapint_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
++u_int	pcapint_filter(const struct bpf_insn *, const u_int, const u_char *,
++    u_int, u_int);
+ 
+ /*
+  * Routine to validate a BPF program.
+diff --git a/pcap-linux.c b/pcap-linux.c
+index 20802e43..7e04a041 100644
+--- a/pcap-linux.c
++++ b/pcap-linux.c
+@@ -4279,6 +4279,7 @@ static int pcap_handle_packet_mmap(
+ 		aux_data.vlan_tag = tp_vlan_tci & 0x0fff;
+ 
+ 		if (pcapint_filter_with_aux_data(handle->fcode.bf_insns,
++					      handle->fcode.bf_len,
+ 					      bp,
+ 					      tp_len,
+ 					      snaplen,
+diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c
+index 344bae47..ade53ea6 100644
+--- a/pcap-netfilter-linux.c
++++ b/pcap-netfilter-linux.c
+@@ -257,8 +257,8 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
+ 
+ 				gettimeofday(&pkth.ts, NULL);
+ 				if (handle->fcode.bf_insns == NULL ||
+-						pcapint_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
+-				{
++				    pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++				                   payload, pkth.len, pkth.caplen)) {
+ 					handlep->packets_read++;
+ 					callback(user, &pkth, payload);
+ 					count++;
+diff --git a/pcap-netmap.c b/pcap-netmap.c
+index f17f36ca..925f677f 100644
+--- a/pcap-netmap.c
++++ b/pcap-netmap.c
+@@ -79,7 +79,8 @@ pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf)
+ 	const struct bpf_insn *pc = p->fcode.bf_insns;
+ 
+ 	++pn->rx_pkts;
+-	if (pc == NULL || pcapint_filter(pc, buf, h->len, h->caplen))
++	if (pc == NULL ||
++	    pcapint_filter(pc, p->fcode.bf_len, buf, h->len, h->caplen))
+ 		pn->cb(pn->cb_arg, h, buf);
+ }
+ 
+diff --git a/pcap-npf.c b/pcap-npf.c
+index f638bd80..38e985bd 100644
+--- a/pcap-npf.c
++++ b/pcap-npf.c
+@@ -720,7 +720,8 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+ 		 */
+ 		if (pw->filtering_in_kernel ||
+ 		    p->fcode.bf_insns == NULL ||
+-		    pcapint_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
++		    pcapint_filter(p->fcode.bf_insns, p->fcode.bf_len,
++		                   datap, bhp->bh_datalen, caplen)) {
+ #ifdef ENABLE_REMOTE
+ 			switch (p->rmt_samp.method) {
+ 
+diff --git a/pcap-rdmasniff.c b/pcap-rdmasniff.c
+index fd6d6fa6..5f15d4c5 100644
+--- a/pcap-rdmasniff.c
++++ b/pcap-rdmasniff.c
+@@ -170,7 +170,8 @@ rdmasniff_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *u
+ 		pktd = (u_char *) handle->buffer + wc.wr_id * RDMASNIFF_RECEIVE_SIZE;
+ 
+ 		if (handle->fcode.bf_insns == NULL ||
+-		    pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
++		    pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++		                   pktd, pkth.len, pkth.caplen)) {
+ 			callback(user, &pkth, pktd);
+ 			++priv->packets_recv;
+ 			++count;
+diff --git a/pcap-snf.c b/pcap-snf.c
+index d08275ac..8a57eadd 100644
+--- a/pcap-snf.c
++++ b/pcap-snf.c
+@@ -190,7 +190,8 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+ 			caplen = p->snapshot;
+ 
+ 		if ((p->fcode.bf_insns == NULL) ||
+-		     pcapint_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
++		     pcapint_filter(p->fcode.bf_insns, p->fcode.bf_len,
++		                    req.pkt_addr, req.length, caplen)) {
+ 			hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision);
+ 			hdr.caplen = caplen;
+ 			hdr.len = req.length;
+diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c
+index bc39b1db..d219721a 100644
+--- a/pcap-usb-linux.c
++++ b/pcap-usb-linux.c
+@@ -733,8 +733,8 @@ usb_read_linux_bin(pcap_t *handle, int max_packets _U_, pcap_handler callback, u
+ 	pkth.ts.tv_usec = info.hdr->ts_usec;
+ 
+ 	if (handle->fcode.bf_insns == NULL ||
+-	    pcapint_filter(handle->fcode.bf_insns, handle->buffer,
+-	      pkth.len, pkth.caplen)) {
++	    pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++	                   handle->buffer, pkth.len, pkth.caplen)) {
+ 		handlep->packets_read++;
+ 		callback(user, &pkth, handle->buffer);
+ 		return 1;
+@@ -921,8 +921,8 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch
+ 			pkth.ts.tv_usec = hdr->ts_usec;
+ 
+ 			if (handle->fcode.bf_insns == NULL ||
+-			    pcapint_filter(handle->fcode.bf_insns, (u_char*) hdr,
+-			      pkth.len, pkth.caplen)) {
++			    pcapint_filter(handle->fcode.bf_insns, handle->fcode.bf_len,
++			                   (u_char*) hdr, pkth.len, pkth.caplen)) {
+ 				handlep->packets_read++;
+ 				callback(user, &pkth, (u_char*) hdr);
+ 				packets++;
+diff --git a/pcap.c b/pcap.c
+index a076c5fb..6caa052b 100644
+--- a/pcap.c
++++ b/pcap.c
+@@ -4349,7 +4349,7 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
+ 	const struct bpf_insn *fcode = fp->bf_insns;
+ 
+ 	if (fcode != NULL)
+-		return (pcapint_filter(fcode, pkt, h->len, h->caplen));
++		return (pcapint_filter(fcode, fp->bf_len, pkt, h->len, h->caplen));
+ 	else
+ 		return (0);
+ }
+diff --git a/pcap_offline_filter.3pcap b/pcap_offline_filter.3pcap
+index 94b9a719..c6d62dee 100644
+--- a/pcap_offline_filter.3pcap
++++ b/pcap_offline_filter.3pcap
+@@ -17,7 +17,7 @@
+ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ .\"
+-.TH PCAP_OFFLINE_FILTER 3PCAP "7 April 2014"
++.TH PCAP_OFFLINE_FILTER 3PCAP "12 March 2026"
+ .SH NAME
+ pcap_offline_filter \- check whether a filter matches a packet
+ .SH SYNOPSIS
+@@ -45,10 +45,35 @@ points to the
+ structure for the packet, and
+ .I pkt
+ points to the data in the packet.
++.PP
++In the
++.B \%bpf_program
++structure the
++.B \%bf_insns
++member is either
++.B NULL
++(which means to reject all packets) or points to an array of one or more
++.B \%struct bpf_insn
++elements, in which case the
++.B \%bf_len
++member must be set to the number of elements (this is what
++.BR \%pcap_compile ()
++produces).
++.PP
++The filter program must have been compiled for a link-layer header type
++that matches the packet data; also on Linux the filter must not use
++BPF extensions, see
++.BR \%pcap_compile ()
++for more information.
+ .SH RETURN VALUE
+ .BR pcap_offline_filter ()
+ returns the return value of the filter program.  This will be zero if
+ the packet doesn't match the filter and non-zero if the packet matches
+ the filter.
++.SH BACKWARD COMPATIBILITY
++.PP
++In libpcap releases before 1.10.7 this function ignored the provided
++.B \%bf_len
++value.
+ .SH SEE ALSO
+ .BR pcap (3PCAP)
+diff --git a/savefile.c b/savefile.c
+index c711a81c..49ef52b6 100644
+--- a/savefile.c
++++ b/savefile.c
+@@ -685,7 +685,8 @@ pcapint_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+ 		 * and, if it passes, process it.
+ 		 */
+ 		if ((fcode = p->fcode.bf_insns) == NULL ||
+-		    pcapint_filter(fcode, data, h.len, h.caplen)) {
++		    pcapint_filter(fcode, p->fcode.bf_len,
++		                   data, h.len, h.caplen)) {
+ 			(*callback)(user, &h, data);
+ 			n++;	/* count the packet */
+ 			if (n >= cnt)
diff --git a/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb b/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb
index 265c46e3bd..aa5265a54c 100644
--- a/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb
+++ b/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb
@@ -13,6 +13,7 @@ DEPENDS = "flex-native bison-native"
 SRC_URI = "https://www.tcpdump.org/release/${BP}.tar.xz \
 	   file://0001-Fix-error-messages-about-32-bit-integer-overflow.patch \
 	   file://01-CVE-2026-0799.patch \
+	   file://02-CVE-2026-31912.patch \
           "
 SRC_URI[sha256sum] = "ec97d1206bdd19cb6bdd043eaa9f0037aa732262ec68e070fd7c7b5f834d5dfc"
 
