The libwebp problem — when one bundled library breaks a hundred apps
When Apple's Security Engineering and Architecture team disclosed CVE-2023-4863 in September 2023, the headlines said "Chrome". The real story was every Electron app on your fleet, every Plex install thumbnailing artwork, every Home Assistant box rendering a dashboard card, and every browser anyone you know runs. The bug lived in libwebp — a tiny, useful, almost invisible library — and because libwebp gets bundled into hundreds of products, "patching CVE-2023-4863" was not one task. It was a long tail of separate tasks per application vendor, stretching across months.
What libwebp does and why it's everywhere
libwebp is Google's reference implementation of the WebP image format. WebP exists because Google wanted a single image format that compressed better than JPEG for photos and better than PNG for graphics with transparency. By 2018 it was supported in Chrome, by 2019 in Firefox, by 2020 in Safari. The format won, and once it won, every application that touches images needed to decode it.
"Every application that touches images" is a much longer list than you'd expect. Obviously browsers. But also: every desktop app built on Electron (which bundles a full Chromium, including libwebp). Every server-side image-processing pipeline that uses ImageMagick, Pillow, libheif, or sharp. Every media library that generates thumbnails — Plex, Jellyfin, Immich, PhotoPrism, Nextcloud. Every dashboard that displays uploaded images — Home Assistant, Grafana with image panels, Bookstack. Every chat client that previews link cards — Slack, Teams, Discord, Signal Desktop. Every code editor that renders Markdown images — VS Code, Notion. Every password manager that displays site favicons — 1Password, Bitwarden's desktop app.
In each of those products libwebp is statically linked or vendored into the application bundle. The application doesn't ask the system "where is libwebp?" — it ships its own copy and links against that. From the application's perspective this is good engineering. From a fleet-security perspective it means one upstream CVE turns into a hundred downstream patch timelines.
The September 2023 disclosure timeline
The narrative arc of CVE-2023-4863 is informative because it explains why so many homelab fleets carried the bug for months without realising it.
September 7, 2023. Citizen Lab and Apple jointly disclose the BLASTPASS exploit chain — an iOS Safari 0-day being used in the wild by NSO Group's Pegasus spyware to target iPhones via iMessage PassKit attachments. Apple ships iOS 16.6.1 and macOS 13.5.2 the same day. The advisory is sparse: "an attacker may be able to cause arbitrary code execution while processing a maliciously crafted image". No CVE number yet for the underlying bug.
September 11, 2023. Google publishes the advisory: CVE-2023-4863, "heap buffer overflow in WebP in Google Chrome prior to 116.0.5845.187". The advisory frames it as a Chrome vulnerability. Chromium-derivative browsers — Edge, Brave, Vivaldi, Opera — start shipping their own updates over the next several days. The wording suggests "this is a Chrome bug, you need to update Chrome".
September 12, 2023. The libwebp project tags
version 1.3.2 with the fix to BuildHuffmanTable.
Researchers reading the Chromium commit notice the patched code
is not a Chrome WebP rendering layer — it's the upstream
libwebp Huffman-table builder, in a file Chromium pulls
verbatim from the libwebp project. The bug is in libwebp, not
in Chrome's use of libwebp.
September 13–14, 2023. Firefox 117.0.1 ships with libwebp updated. Linux distributions begin backporting the libwebp 1.3.2 fix into their stable libwebp packages — Debian, Ubuntu, Fedora, Rocky, Alma all push security updates within 48 hours. The system-package layer is mostly patched within a week.
Mid-September 2023. The Electron project ships updated builds (covering the active 22.x, 24.x, 25.x, and 26.x release lines) that include the fixed libwebp. Crucially, those Electron releases do not automatically update apps built on Electron. Each Electron-app vendor has to pick up the new Electron release, build a new version of their app, and ship it. The clock now starts for hundreds of Electron apps independently.
October and November 2023. Most actively- maintained Electron apps — Slack, VS Code, Signal Desktop, 1Password — ship updates that pull in the new Electron release. Some take weeks because the Electron version bump requires compatibility work. Some Electron apps on slower release cadences (smaller open-source tools, abandoned-feeling commercial apps) take months.
Throughout late 2023 and into 2024. Server-side apps that bundle libwebp for image processing — Home Assistant add-ons, Plex Media Server, Jellyfin, the *arr suite — update on their own cadence. Home Assistant's core image_processing integrations pulled in a fixed Pillow/libwebp combination within a few releases. Plex took longer because Plex bundles its own image-processing toolchain and re-builds it on Plex's schedule. The *arr suite — which all share a common .NET image-handling stack — took longer still.
The takeaway. "Patched CVE-2023-4863" is not a single moment in time. It's a long ramp where each application vendor moves at their own pace, and a homelab's actual exposure window stretches as long as the slowest-moving app on the box. If your Plex server got its libwebp fix in October but your Sonarr container was still on a pre-September build until January, your fleet carried the bug into 2024.
The bundled-library pattern
Step back from the specifics of libwebp and the pattern generalises. When a critical bug is found in a widely-bundled library, three things happen at different speeds:
The upstream fix is fast. libwebp 1.3.2 shipped one day after the public CVE. Open-source projects with active maintainers and a clear bug to fix can move within hours. This is the good news.
The system-package layer is medium-fast. Distro
maintainers backport the fix into their stable libwebp package,
push the security update, and apt update or
dnf update deploys it. Most distros were done
within a week. If you run unattended-upgrades on your homelab
boxes, the system libwebp got patched without you doing
anything.
The bundled layer is slow and uneven. Every application that vendored libwebp has to re-build, re-test, and re-ship its own release. Some do this in days. Some in weeks. Some in months. Some never do, because the project is no longer actively maintained or because the maintainer didn't notice that their dependency had a security fix.
The "double counting" problem makes this worse. Chrome got CVE-2023-4863 — that's the canonical number. But Slack shipping an old Electron with vulnerable libwebp also has the same bug, reachable the same way. Slack didn't get its own CVE for "Slack ships vulnerable libwebp" — there is no separate CVE for every Electron app that re-bundled the affected library. A scanner that watches only the canonical CVE list and matches it against system packages will report your machine clean, even when your Slack icon in the menu bar is happily decoding WebP files with a vulnerable library.
This isn't a theoretical concern. The patching gap in self-hosted services post covers the broader pattern: downstream re-bundlers always lag upstream, and the lag is invisible to the user until something breaks.
Mapping the "did I patch it?" question for your homelab
For any given Linux box in your homelab, "is libwebp patched?" decomposes into concentric rings. Each ring has a different patch path and a different owner.
Ring 1 — system libwebp. The shared library
installed by your package manager. This is what
apt list --installed libwebp7 or
rpm -q libwebp shows you. It's used by
command-line tools (cwebp, dwebp),
ImageMagick if installed from the distro repo, anything else
that dlopens the system library. If you run
unattended-upgrades or you've run a manual update since
September 2023, this is patched. Easy ring.
Ring 2 — browser libwebp. Chrome auto-updates itself within hours of a vendor release if the user lets it. Firefox auto-updates similarly. Safari is patched via macOS or iOS system updates. The Chromium-derivative browsers all shipped fixes in mid-to-late September 2023. If you've restarted your browsers since then, you're covered. This ring is mostly self-healing.
Ring 3 — Electron-app libwebp. Each Electron app's individual update cadence. Slack auto-updates fairly aggressively; VS Code prompts on launch; 1Password updates quickly because security is their pitch. Other Electron apps can sit on old versions for months. Auto-update may be disabled by default, or the app may only update when launched (so a rarely-used app stays vulnerable). The honest answer for this ring: check each Electron app on each machine individually, and turn on auto-update everywhere.
Ring 4 — server-side image-processing pipelines. Plex, Jellyfin, Home Assistant, the *arr suite, Immich, PhotoPrism, Nextcloud preview generators. Each of these bundles its own image-processing stack, and each updates on its vendor's schedule. The answer here is per-application: check the vendor's changelog for a libwebp-related update after September 12, 2023. If you can't find one, assume vulnerable. Container deployments inherit this problem in doubled form, because a container image frozen at a specific tag in August 2023 still contains the vulnerable libwebp today — even if the upstream image has long since been rebuilt.
Working through these rings for one box is tedious but tractable. Working through them for a homelab of ten or twenty boxes is the kind of task that quietly never happens. That's the gap a continuous scanner is supposed to close — see continuous CVE scanning vs patching for the longer argument.
What a scanner can and can't catch
Here's the honest line on Noxen for this specific CVE:
Noxen catches Ring 1. The agentless SSH probe inventories the system libwebp package on every host and matches the version against the daily-refreshed CVE feed. If a host is running an unpatched system libwebp, Noxen surfaces it with the right severity and the right remediation pointer. Distro-aware version comparison means a Debian 12 box with the backported fix is correctly recognised as patched even though the version string doesn't equal "1.3.2".
Noxen does not yet catch Ring 2, Ring 3, or Ring 4. Detecting
statically-linked libwebp inside Chrome, inside an Electron
app, or inside a Plex container would require either binary
introspection (parsing ELF symbols and matching against known
library fingerprints) or SBOM-aware scanning (reading SBOMs
from container registries and matching package lists against
CVE data). Both are possible. Neither is in the Noxen scope
today. The roadmap entry for this work is
LanguagePackageProbe, which will start with
language-ecosystem package manifests (npm, pip, gem) before
tackling vendored binary libraries.
Pretending otherwise would be a worse position than admitting the limit. A scanner that says "you're clean" because it checked Ring 1 and ignored Rings 2–4 is giving you false confidence. The mental model to hold while running Noxen is: Ring 1 is automated, Rings 2–4 are policy and discipline. Noxen handles the part of the problem that scales; you handle the part that needs vendor-by-vendor attention.
Defence-in-depth around the bundled layer
Given that Rings 2–4 are slow and uneven, the practical move is to assume some application on your fleet is going to lag a libwebp-class CVE by months and design for that case.
Network isolation for image-processing services. Plex, Jellyfin, Immich, PhotoPrism, *arr — these services decode images from a long tail of sources (downloaded artwork, uploaded photos, metadata-provider responses). Putting them on a dedicated VLAN with no path to your trusted hosts means a successful RCE against the image-processing service does not immediately become an RCE against your password manager or your dotfiles. The Home Assistant security checklist covers the VLAN approach for one common case; the pattern generalises.
Untrusted-image quarantine. If you run a
service that accepts user-uploaded images — Nextcloud,
Immich, PhotoPrism — the upload pipeline is your highest-risk
surface for an image-decoder CVE. A sandboxed conversion step
(running the image-processing tool inside a minimal container
with no network access and no host-filesystem access beyond
the upload directory) limits blast radius. ImageMagick's
policy.xml restrictions and Pillow's
PIL.Image.MAX_IMAGE_PIXELS are simpler mitigations
that catch the easy cases.
Browser updates as critical infrastructure. Browsers are the most frequently attacked image-decoders on a homelab admin's machine. If you've disabled auto-updates in Chrome or Firefox because they're annoying, re-enable them. If you run Brave or Vivaldi, check that auto-update is on. Browsers are where image-decoder CVEs reach you fastest, and they're where the patch arrives fastest too — but only if you let the auto-updater do its job.
Electron-app auto-update. Most Electron apps have auto-update on by default. Some power users turn it off because they don't like restart prompts. Don't. For libwebp-class CVEs, the auto-updater is the only thing standing between you and a year-old vulnerable libwebp inside a chat client.
Container image refresh policies. If you run
Plex, Jellyfin, Home Assistant, or *arr in containers, your
container is only as patched as the last time you pulled the
image. A watchtower-style auto-refresh for
non-critical services, plus a documented weekly manual
docker compose pull cadence for the rest, keeps
the bundled-libwebp layer fresh. Pin tags only when you have
a specific reason; rolling tags inherit upstream fixes.
The parallel with the xz-utils backdoor
The xz-utils backdoor (CVE-2024-3094) is a completely different mechanism — a deliberate supply-chain attack rather than an accidental memory-safety bug — but the structural lesson is identical. In both stories the actual bug was tiny and easily-patched once known. In both stories the hard problem was tracking exactly which downstream products inherited the bug, and how long each of them took to ship a fix.
With xz the inheritance was through linker chains and distro builds. With libwebp it's through application bundling. The mechanisms differ, but the buyer-stage realisation is the same: you cannot audit every dependency on your fleet by hand. The number of libraries times the number of products times the number of hosts is too large. The only sustainable response is some combination of (a) automated scanning that catches what it can, (b) defence-in-depth so that the rings the scanner can't see don't immediately become a fleet-wide compromise, and (c) discipline about keeping auto-update on everywhere it's safe to do so.
Both CVEs also rewarded a specific homelab posture: running
stable distro releases with unattended-upgrades enabled. The
system-package layer got fixed automatically, without anyone
doing anything, because someone else's pipeline was already
pushing the patch. The fleets that struggled were the ones
that disabled unattended-upgrades for stability reasons, or
that ran rolling-release boxes and didn't run
pacman -Syu for a few weeks. Boring updates beat
heroic incident response.
Where Noxen fits in
Noxen is built for the part of the problem that scales: agentless inventory of every Linux host on your fleet, matched continuously against a daily-refreshed CVE feed, with distro-aware version comparison so backports get credited correctly. For CVE-2023-4863 that means the system libwebp on every enrolled host is checked on every scan, and any unpatched host shows up in the report with the right severity and remediation pointer.
Noxen does not, today, detect statically-linked libwebp inside Electron apps or container images. The roadmap entry for that work exists; the honest line for now is that Noxen catches Ring 1 and the other three rings are on you and your application vendors. That limit is by design — system-package scanning is the layer where automation reliably beats manual effort, and we'd rather be honest about the boundary than ship false confidence.
Noxen runs on your Mac, scans your Linux fleet over SSH (no agents, no SaaS round-trip), and surfaces what changed since the last scan — new CVEs, configuration drift, newly exposed admin services. If the libwebp problem makes you want a better answer to "what's actually installed across my fleet, and is it patched?", that's the problem Noxen solves.
Further reading
- CVE-2023-4863 reference card — per-distro fix versions, scan commands, CVSS and KEV details.
- CVE-2024-3094 (xz/liblzma backdoor) for homelabs — the parallel supply-chain story with a different mechanism but the same lesson.
- The patching gap in self-hosted services — why downstream re-bundlers lag upstream, generalised.
- Continuous CVE scanning vs patching — why both are necessary, and how they interact.
- Home Assistant security checklist — the VLAN-isolation pattern for image-processing integrations.
- Citizen Lab's BLASTPASS disclosure — the in-the-wild use of CVE-2023-4863 against iOS Safari via iMessage.
- Isosceles's technical breakdown of the WebP 0-day — the most readable explanation of the BuildHuffmanTable bug at the source-code level.
Want this kind of monitoring across your fleet? Noxen scans every Linux/BSD/macOS host you own over SSH (no agents) and matches installed package versions against a daily-refreshed CVE feed. Pricing & download.
Scan your Linux fleet from your Mac
Noxen runs nightly agentless audits over SSH and shows only what changed since the last scan — new CVEs, config drift, newly exposed admin services. Mac-native control plane, no SaaS round-trip.