Triaging kernel CVEs on a router nobody patches anymore: a FRITZ!Box 7412 walkthrough

Linux kernelProduct securityReachabilityCVE triage

A DSL router whose last firmware shipped in 2023, on a kernel branch that died in 2018. We registered it in KernelScan the way any product owner would — version, architecture, the vendor's own .config — and walked the result from 20,059 kernel CVEs down to the handful an attacker can actually reach. This is that walk, step by step.

These boxes don't die, they get demoted

A FRITZ!Box 7412 mounted on a whitewashed basement wall, DSL cable plugged in, the Power/DSL LED solid green FRITZ!OS login page of the FRITZ!Box 7412 at 192.168.178.1 — a single password field labelled Kennwort, no user name, an Anmelden button and a Kennwort vergessen link
Left: the unit behind this article — still on a DSL line, on a basement wall, in 2026. Right: its login page today. One password, no user name; that was normal when this box shipped.

The FRITZ!Box 7412 was the entry-level DSL router AVM built for ISPs to hand out, and for years it was the box that came in the post with a new contract: one LAN port, DSL only, sold from 2016. Its final firmware, FRITZ!OS 06.88, landed on 4 September 2023 — a root-CA update and a WLAN fix — and nothing since. The kernel inside is Linux 3.10.73, the last release the 3.10 branch ever got; upstream support ended in February 2018. Every kernel bug found in the eight years since is unfixed by definition.

How many are still online? Nobody publishes that number, but the shape is clear. An ISP-issued default box ships for years at contract volume, and consumer routers get replaced when they break, not when their kernel does. A device retired from the living room typically gets demoted — to the basement, the holiday flat, the parents' house — rather than binned. Multiply those three things and you get a fleet still measured in thousands, every unit answering on a public IPv6 address — and, on the shrinking share of lines without DS-Lite, a public IPv4 one — on a kernel frozen in 2015. The exact count matters less than two facts: it isn't zero, and not one of those boxes will ever receive another kernel fix.

So this is a product-lifecycle question, not a museum piece: what does an honest kernel-CVE picture for it look like, and how much of it actually matters? Here is how we answered that with KernelScan — five steps that apply to any Linux-based appliance you are responsible for.

Step 1 — Start from the vendor's config, not a guess

A CVE verdict is only as good as the configuration evidence behind it, so the first job is the real .config. AVM publishes GPL source drops per device and firmware generation; for the 7412 the artifact is source-files-FRITZ.Box_7412-vr9-06.87.tar.gz from osp.avm.de, and the exact .config the device was built with sits in the kernel tree inside it. One check closes the loop: the 06.88 firmware ships the same kernel binary the 06.87 tree produced — build banner October 2021, gcc 4.8.3 — so the last firmware update touched userspace, not the kernel. The config we analyzed is the config running on every 7412 in the field.

What it describes: a Lantiq VR9 SoC, MIPS32 34Kc big-endian, two 500 MHz cores, CONFIG_SMP=y, 558 options set to =y in total, and none of the hardening that kernels grew after 2016. Keep that last point; it comes back at the end.

If the product is your own, this step is trivial — you have the build. If it is a vendor's, the GPL drop is where the evidence lives. A nearest-neighbour distro config is not evidence.

Step 2 — Register the product and read the funnel

In KernelScan a product is a kernel version, an architecture and a .config. We registered 3.10.73 / mips with the AVM config and let the engine map it against the full corpus of 20,059 published Linux kernel CVEs. The result reads as a funnel:

StageCVEsWhat it means
Published Linux kernel CVEs20,059The corpus.
Version range matches 3.10.735,051KernelScan's version-only match — what a scanner sees before any config is consulted. (Dependency-Track with its stock NVD-CPE analyzer shows 4,175 for the same kernel-only SBOM; CPE ranges are sparser than the corpus's per-branch ranges.)
Affected after config mapping595The vulnerable code is compiled into this build. 29 more still in triage.
Affected and CVSS above 827The loud subset — not the same thing as the dangerous one.

The 5,051 is the number a version scanner produces for this box, and it is honest in its own terms: those CVEs really do claim 3.10.73 in their version range. Dependency-Track, fed a one-component SBOM with just the kernel CPE, lands in the same neighbourhood — 4,175 findings, 123 of them critical, on a project with exactly one component. What it cannot tell you is that 4,427 of them concern code AVM never compiled. That is what the config mapping does, and each of the 595 survivors carries the CONFIG_* reasoning that put it there, so the verdict is auditable rather than oracular. The 29 in triage are the honest remainder: old CVEs, most of them from 2015 to 2020, for which nobody knows a fix commit — 27 of the 29 have none on record anywhere — so there is nothing to map, and they stay on the list rather than disappearing into it.

Dependency-Track findings view for the project FRITZ!Box 7412 — FRITZ!OS 06.88 [3.10.73]: severity counters 123 critical, 1486 high, 2475 medium, 91 low; Audit Vulnerabilities tab showing 4175 findings on the single component linux 3.10.73, paginated over 418 pages
Dependency-Track 5.0.2 with its stock NVD analyzer, fed a one-component SBOM carrying only cpe:2.3:o:linux:linux_kernel:3.10.73: 4,175 findings, 123 of them critical, 418 pages — before anyone has asked what this kernel actually contains.
Which list contains which CVEs — kernel 3.10.73 KernelScan version-applicable · 5,051 NVD CPE window covers 3.10.73 · 4,166 4,108 in both lists 479 affected · 16 in triage 3,613 not compiled in 943 only in KernelScan 831 — NVD has no usable version data for the CVE 112 — NVD's window stops short of 3.10 (SegmentSmack) 116 of them affected here 58 only in NVD all excluded on purpose: never fixed anywhere, not in mainline, disputed or invalid All 20,059 kernel CVEs in KernelScan 14,996 also carry a vulnerable NVD kernel CPE 5,063 (25 %) have none in NVD NVD kernel CVEs missing from KernelScan: 2
To scale. Vulnerable-flagged NVD kernel CPEs only — NVD also tags 507 Flash-Player-era CVEs with a non-vulnerable linux_kernel platform CPE, excluded here. NVD queried directly; Dependency-Track's mirror showed 4,175.

The picture is the point: NVD's list sits inside ours. The 58 NVD-only entries are excluded on purpose; the 943 KernelScan-only ones are mostly CVEs NVD carries no usable version data for — and 116 of them are affected on this box. Across the whole corpus, one kernel CVE in four has no NVD kernel CPE at all.

The severity split of the 595 — 15 critical, 243 high, 296 medium, 14 low, 27 informational — is the part to read once and then ignore. On a router, severity tells you how bad a bug is for whoever reaches it; it tells you nothing about whether anyone can.

KernelScan product page for fritzbox-7412: counters 595 affected, 4427 not affected, 0 mitigated by factor, 29 in triage, 3 KEV; severity bars critical 15, high 243, medium 296, low 14; CVE Details with the CISA Known Exploited group expanded to CVE-2016-5195, CVE-2025-38352 and CVE-2017-1000253, and the buckets Affected 595, In triage 29, Not affected — not compiled in 4427
The same kernel in KernelScan, after the config mapping: 595 affected, 4,427 not compiled in, 29 in triage. The three CISA-KEV entries are expanded — DirtyCow, the POSIX-timer race, the PIE stack-clash — and Step 4 explains why all three are local-only on this box.

Step 3 — Read the not-affected reasons: they tell you what the box is

Most teams skip the 4,427 not-affected verdicts. Don't — they are the fastest description of the product's real attack surface you will get. Three patterns on this box:

  • Whole families were never compiled in. No io_uring (it postdates 3.10 by six years), no eBPF JIT, no USB gadget, Bluetooth, DRM or sound drivers on a DSL-only box. CONFIG_USER_NS is unset — which by itself removes the "unprivileged user becomes CAP_NET_ADMIN inside a user namespace" chain that most recent weaponized kernel exploits rely on.
  • Netfilter doesn't exist. CONFIG_IP_NF_IPTABLES and CONFIG_IP6_NF_IPTABLES are not set; there is no iptables binary in the firmware. Every netfilter, x_tables and nftables CVE in the corpus drops out by construction.
  • …which exposes the blind spot. The FRITZ!OS firewall lives inside AVM's proprietary kernel module (kdsldmod), the same binary-only module that owns the DSL/PPPoE data path. Its WAN ingress policy is default-deny, and no CVE feed tracks it. Same for WLAN: AVM ships its own driver, CONFIG_CFG80211/mac80211 are unset, so the well-researched mac80211 CVE family cannot be assessed from kernel-CVE data at all.

The lesson generalizes: on vendor-modified firmware, CVE feeds see the upstream kernel and are blind to the vendor's replacements. A config-level tool at least gets the drop-outs right — an affected list that contains netfilter CVEs for this box is proof nobody looked at the config — but the proprietary parts have to be assessed by other means. Unknown, not safe.

Step 4 — Cut the affected list by reachability, not by score

Now the 595. The cut that matters on an internet-facing appliance is: who can drive the trigger? We swept every affected verdict with one question — can an unauthenticated packet peer reach this code? — using the frame Step 3 established: WAN ingress is default-deny in the proprietary firewall; IPv4 fragment reassembly runs before that filter — but only lines with a public IPv4 address expose it to the internet at all; most consumer DSL lines today are DS-Lite, which puts IPv4 behind carrier-grade NAT and leaves IPv6 as the WAN side that is always there, with a v6 policy in the proprietary firewall nobody can inspect; anything that needs a completed TCP handshake is LAN-side, where the web UI, TR-064 and SIP listeners accept unauthenticated connections; IGMP/MLD and Router Advertisements are link-scoped. Two buckets fall out.

Local-first bugs — the weaponized ones. KernelScan's exploit-maturity overlay flags 18 of the 595 with public exploit material: 12 weaponized, 6 proof-of-concept, 3 on CISA's KEV list. All twelve weaponized entries are local primitives on this box: DirtyCow (CVE-2016-5195), the UFO write (CVE-2017-1000112), the af_packet ring bugs (CVE-2017-7308, CAP_NET_RAW), the POSIX-timer race (CVE-2025-38352), the PIE stack-clash (CVE-2017-1000253), and the CAP_NET_ADMIN-gated family whose usual entry hatch — a user namespace — this kernel doesn't have. They need code already running on the box; from outside, they do nothing. Notably, none of the 27 high-score entries carries public exploit material: the scary-score set and the exploitable-for-real set barely overlap.

Remote-reachable bugs — the packet-path DoS class. This is what an outside attacker actually gets:

CVE · CVSSFromWhat it does here — and how sure we are
CVE-2018-5391 FragmentSmack · 7.5WAN, public-IPv4 linesIPv4 fragment reassembly, ahead of the firewall. Source-verified and bench-tested — see Step 5.
CVE-2018-5390 SegmentSmack · 7.5LANTCP out-of-order queue collapse against any unauthenticated listener. Source-verified. NVD's version range says this kernel is immune — see Step 5.
CVE-2019-11477 / -11478 · 7.5 / 5.3LANSACK-driven exhaustion riding the same collapse cost. Engine verdict.
CVE-2023-52881 · 9.8LANHostile ACKs of never-sent bytes corrupt send state. The 9.8 is vector math; the realistic outcome is a dropped connection. Engine verdict.
CVE-2023-1206 · 5.7LANIPv6 connection-lookup hash collisions — a SYN-flood shape. The only remote-reachable entry with a public PoC. Engine verdict.
IPv6 / IGMP / MLD parse family · 8.8–9.8 (CVE-2026-43198, -63924, -72322, -72323, -53275)LAN, on-linkCrash-grade races and use-after-frees driven by received queries and options. Engine verdicts, one at 0.7 confidence; none source-verified.
UDP receive family · 7.8 / 5.0 (CVE-2015-5364, -5366)LANBad-checksum floods hang the box; a mishandled error return stalls readers. Engine verdict.
The RCE asterisks · 9.8 / 9.8 (CVE-2016-7117, CVE-2016-10229)LANNVD claims remote code execution via recvmmsg / MSG_PEEK error paths. Needs a receiving daemon using that call pattern; the userspace that would prove it is proprietary. Low reachability, not zero.

Below the line: Router Advertisement config nudges, an RA stack-byte leak, TCP timing side channels — reconnaissance, not impact. And a set of 9.x entries that parse packets but need a local ingredient (a tun/tap-injected GSO flag, a raw protocol-255 socket, TCP-MD5 sessions) that nothing on this box supplies.

Read the table as one sentence: everything an outside packet can trigger here is CPU starvation, a crash, a leaked byte or a config nudge — never a write primitive. No remote kernel RCE was found in the mapped surface. That is a weaker claim than "none exists", and the two RCE-asterisk rows are exactly where the weakness sits.

KernelScan CVE detail for CVE-2016-5195 (DirtyCOW): AI risk summary and vulnerability analysis, then Exploit Availability — CISA lists this CVE as known exploited in the wild, with three public exploit repositories listed KernelScan CVE detail for CVE-2023-1206 (IPv6 hash collision DoS): affected branches, AI risk summary and analysis, then Exploit Availability — proof-of-concept code is publicly available, not evidence of exploitation in the wild, one repository listed
The exploit-maturity overlay on two of the 595. Left: DirtyCow — KEV-listed, three public exploits, every one of them needs code already running on the box. Right: CVE-2023-1206 — the only remote-reachable entry with public PoC code, a SYN-flood-shaped DoS and explicitly "not evidence of exploitation in the wild."

Step 5 — Verify the top candidates at source, and if you can, on hardware

A config-mapping verdict says the vulnerable code is compiled in. For the entries that will decide your risk statement, go one level down. We did it for the two Smacks, and each taught a different lesson.

SegmentSmack: the version range lies. NVD scopes CVE-2018-5390 to kernels 4.9 through 4.18, so a version check clears 3.10.73. The shipped AVM source says otherwise: the routine the bug lives in — the one that collapses a TCP connection's out-of-order queue — is there, and the guard the 4.18 fix added is not. KernelScan had flagged it before anyone opened the source, for a reason worth knowing: this CVE predates the kernel's own CVE process, so its record carries no "introduced in" version, and without a lower bound the engine does not clear it by version at all — it only asks whether the fixed file is compiled into this build, and it is. A conservative default that turned out to be right, and exactly the kind of surprise a CPE match cannot see.

FragmentSmack: the hardware pushed back. On paper this is the box's worst case: the vulnerable code is compiled in, unchanged from vanilla, and it runs before the firewall gets a say — so anyone who can send IP fragments to the box's public IPv4 address could, in theory, tie up its CPU from the internet. So we tried it on the bench unit. It didn't fall over. The box keeps far less memory for fragment reassembly than the attack assumes — about a fifth of stock — so the long fragment chains the public exploits rely on never build up, and a two-minute flood at the rate that should have saturated a core left latency, web response and WAN throughput exactly where they were. That is not a clean bill of health: push the rate several times higher — easy on a wired gigabit link, beyond what we tested — and a core may still give out. But "anyone with a script" became "an attacker with real bandwidth, against a ceiling nobody has measured."

Two verifications, two corrections in opposite directions: one CVE the feed said doesn't apply, and does; one the model said would kill the box, and didn't at the tested rates. Neither correction is available from a dashboard number.

What the triage says

  • Remote kernel RCE: none found. Every weaponized memory-corruption bug in the affected set is local-first on this configuration.
  • WAN availability: real but rate-gated — and line-dependent. The strongest candidate is source-present, structurally pre-firewall, and blunted by an accidental memory cap whose ceiling nobody has measured; it needs a public IPv4 address, which a DS-Lite line doesn't have. The IPv6 side is public on every line, and what the proprietary firewall lets through there is unobservable.
  • LAN availability: likely. Source-verified vulnerable code reachable by any on-link host with no authentication; not yet benched.

And one thing the CVE list cannot express but the config can: once anything lands on this box, the kernel puts up no fight. No KASLR (it doesn't exist on MIPS in 3.10), no stack protector, no RWX enforcement, no hardened usercopy, no SMEP/SMAP analogue on a 34Kc core, a deterministic allocator, and /dev/kmem compiled in. A modern exploit chain has three or four stages because each mitigation forces one; here DirtyCow — present in the shipped source, with public MIPS exploits — is one primitive, one stage, root. Hard to enter, trivial to own once inside: that is the signature of an unhardened 2013 kernel carrying 2026 traffic.

What to do with one

Retire it. Not because of the critical count — that number was mostly noise — but because the availability exposure lives in the kernel, upstream of the firewall, and is unfixable in software: the branch is dead and the kernel is frozen in the box. Freetz-NG doesn't change that — it repacks AVM's stock kernel.image unchanged, because the proprietary DSL, WLAN and DECT modules are bound to that exact build; it can trim userspace listeners, nothing more. OpenWrt on the VR9 platform would replace the kernel but also the box's reason to exist (DSL, VoIP and DECT stay behind), and support for this specific model is experimental. If you keep one, keep it as a lab box on a trusted LAN — that is honestly the best thing it can be now.

The template

Everything above is five steps, and none of them is specific to AVM:

  1. Get the real .config — your build, or the vendor's GPL drop. Not a distro neighbour.
  2. Register the product (version, arch, config) and read the funnel: corpus → version-matched → affected. The gap between the last two is your scanner's false-positive rate.
  3. Read the not-affected reasons — they map the product, and they show where the CVE feed is blind (vendor replacements, proprietary modules).
  4. Cut the affected set by who can reach the trigger, with exploit maturity as the overlay; separate local-first from remote-reachable before you look at a single score.
  5. Verify the entries that decide your statement at source — and, if you have hardware, on the bench. Expect corrections in both directions.

KernelScan does steps 2–4 as a product scan with per-CVE reasoning you can audit; steps 1 and 5 are yours, and they are the ones that turn a list into a defensible position. If you ship anything with a Linux kernel in it — router, camera, controller, NAS — upload the config and start with the funnel.

A final note: we're staying tuned

The box stays registered in KernelScan, and the daily digest is switched on:

KernelScan product page, Email alerts section: a ticked checkbox labelled 'Email me a daily digest of newly-affecting CVEs', with the note that alerts are per team member and part of the plan

What that checkbox does: once a day, if a newly published CVE maps to affected on this exact configuration, you get one email listing it. Nothing new, no mail. Anyone with a product in KernelScan can switch it on. So when the next kernel CVE lands on this 3.10.73 build, we hear about it the next morning — and if it changes any verdict in this article, we will say so here.

All configuration evidence derives from AVM's GPL source release for the device. CVE verdicts and exploit-maturity data are the KernelScan corpus and product scan of 2026-09-20 — a snapshot that moves as CVEs are published and scores revised. Source-level verification was done in the vendor's published kernel tree. All tests were performed on our own physical FRITZ!Box 7412, running the analyzed firmware, on 2026-09-20 — delivery canaries, depth sweep, rate ladder 500–12,500 pps, and a WAN forwarding probe under storm. No third-party devices were touched. FRITZ!Box and FRITZ!OS are trademarks of AVM GmbH; Dependency-Track is a project of the OWASP Foundation. Names are used for identification only — no affiliation with or endorsement by either is implied.