Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2025-55286

CVE-2025-55286: z2d Graphics Library Buffer Overflow Flaw

CVE-2025-55286 is a buffer overflow vulnerability in z2d v0.7.0 affecting MSAA rendering. Out-of-bounds access in coverage buffers can lead to memory corruption. This article covers technical details, affected versions, and mitigation.

Updated:

CVE-2025-55286 Overview

CVE-2025-55286 is an out-of-bounds access vulnerability in z2d, a pure Zig 2D graphics library. The flaw was introduced in z2d v0.7.0 alongside a new multi-sample anti-aliasing (MSAA) implementation that uses a dedicated coverage buffer instead of the previous alpha mask surface. When a drawing path extends partly or wholly outside the rendering surface, incorrect bounding calculations cause out-of-bounds writes into the coverage buffer. The issue affects Context.fill, Context.stroke, painter.fill, and painter.stroke when using the .default or .multisample_4x anti-aliasing modes.

Critical Impact

In non-safe optimization builds (ReleaseFast or ReleaseSmall), the out-of-bounds access can lead to invalid memory accesses or memory corruption in the host process.

Affected Products

  • z2d 2D graphics library, version 0.7.0
  • Applications built with ReleaseFast or ReleaseSmall optimization modes are most exposed
  • Drawing pipelines using .default or .multisample_4x anti-aliasing (.supersample_4x and no-AA are not affected)

Discovery Timeline

  • 2025-08-16 - CVE-2025-55286 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2025-55286

Vulnerability Analysis

The vulnerability is a memory boundary violation classified as [CWE-119]. z2d v0.7.0 introduced a SparseCoverageBuffer used by the new MSAA path to store per-pixel coverage data in super-sampled coordinates. When a caller submits a drawing path that extends beyond the target surface, the painter passes span coordinates into addSpan without correctly clamping them against the buffer capacity. The buffer then grows or writes past its allocated region.

Because z2d is a library, the practical impact depends on the consuming application. A malicious or malformed input document, such as a crafted SVG-like path or attacker-controlled geometry, can trigger the condition inside a host application that renders untrusted graphics.

Root Cause

The root cause is missing capacity validation in SparseCoverageBuffer.addSpan combined with incorrect edge clamping in painter.zig. The pre-patch code called math.clamp(edge, 0, sfc_width - 1) on both edge endpoints, which silently pinned out-of-range values to valid pixel indices instead of skipping the span, causing the span length to be miscomputed. The coverage buffer then received writes beyond its capacity.

Attack Vector

Exploitation requires the attacker to influence the drawing path submitted to a z2d-based renderer, for example through a file, network payload, or API input processed by the host application. The bug is only reachable when .default or .multisample_4x anti-aliasing is used. Safe optimization modes (Debug, ReleaseSafe) will trap on the out-of-bounds access; ReleaseFast and ReleaseSmall builds may silently corrupt adjacent memory.

text
// Patch excerpt: src/internal/sparse_coverage.zig
// Adds a hard capacity check inside addSpan so out-of-range writes panic
// instead of corrupting memory.
    pub fn addSpan(self: *SparseCoverageBuffer, x: u32, len: u32) void {
        if (x + len > self.capacity * scale) {
            @panic("attempt to add span beyond capacity. this is a bug, please report it");
        }

        if (len == 0) return;

        // Start co-ordinates and coverage

Source: GitHub commit 93e45d3

text
// Patch excerpt: src/painter.zig
// Replaces the flawed clamp of start_x with a max() plus an explicit
// break when the edge falls past the draw area.
        for (0..edge_list.items.len / 2) |edge_pair_idx| {
            const edge_pair_start = edge_pair_idx * 2;
            const start_x: i32 = @max(0, edge_list.items[edge_pair_start]);
            if (start_x >= sfc_width) {
                // We're past the end of the draw area and can stop drawing.
                break;
            }
            const end_x: i32 = math.clamp(
                edge_list.items[edge_pair_start + 1],
                start_x,

Source: GitHub commit 93e45d3

Detection Methods for CVE-2025-55286

Indicators of Compromise

  • Application crashes, panics, or segmentation faults in processes that render 2D graphics through z2d v0.7.0
  • Unexpected @panic messages referencing SparseCoverageBuffer or coverage capacity in application logs
  • Rendering artifacts or heap corruption warnings when processing paths that extend outside the target surface

Detection Strategies

  • Inventory Zig projects and dependencies for z2d at version 0.7.0 using build manifests such as build.zig.zon
  • Perform fuzz testing of consumer applications with drawing paths that intentionally exceed surface bounds under .default and .multisample_4x anti-aliasing modes
  • Build affected applications with ReleaseSafe or run with AddressSanitizer to surface out-of-bounds accesses during testing

Monitoring Recommendations

  • Monitor endpoint telemetry for repeated crashes of applications that consume untrusted graphics input
  • Correlate process termination events with the receipt of externally supplied vector or path data
  • Track dependency-update events in CI/CD pipelines to confirm removal of z2d v0.7.0 from all builds

How to Mitigate CVE-2025-55286

Immediate Actions Required

  • Upgrade z2d to version 0.7.1 in all projects and rebuild affected binaries
  • Skip v0.7.0 entirely if migrating from an earlier release; move directly to v0.7.1
  • Audit build configurations and prefer ReleaseSafe over ReleaseFast or ReleaseSmall for exposed rendering services until upgrade is confirmed

Patch Information

The fix is contained in GitHub Pull Request #137 and commit 93e45d3, and is described in GitHub Security Advisory GHSA-2vq8-cp8r-vcf3. The patch adds an explicit capacity check in SparseCoverageBuffer.addSpan and replaces the incorrect clamp in painter.zig with a @max plus early-exit when the edge is past the draw area.

Workarounds

  • Switch anti-aliasing to .supersample_4x or disable anti-aliasing, both of which are unaffected code paths
  • Validate and clip drawing paths in the calling application so no coordinates extend outside the rendering surface
  • Restrict rendering of attacker-controlled paths to sandboxed processes until the library is upgraded
bash
# Update z2d dependency to the patched version
zig fetch --save https://github.com/vancluever/z2d/archive/refs/tags/v0.7.1.tar.gz
zig build

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.