Skip to main content
30-Year-Old PNG Library Bug: What Took So Long?Incident
4 min readFor Security Engineers

30-Year-Old PNG Library Bug: What Took So Long?

A vulnerability in libpng went undetected for three decades before it was patched in February 2026. Similarly, Windows PrintDemon lingered in production code for 24 years before Microsoft addressed it in May 2020. These aren't obscure issues in niche projects; they're critical flaws in widely used libraries and operating systems.

If your team manages legacy code, these incidents are relevant. Let's explore what happened, what went wrong, and how you can prevent similar issues.

What Happened

The libpng vulnerability existed from the library's early releases until February 2026. PrintDemon affected Windows printing services from 1996 until its May 2020 patch. Both vulnerabilities persisted through numerous security audits, penetration tests, and code reviews.

These weren't zero-days discovered by attackers first. They were latent defects that survived because traditional review methods couldn't scale to legacy codebases.

Timeline

libpng vulnerability:

  • Initial code introduction: Mid-1990s
  • Discovery: 2025-2026 timeframe
  • Patch release: February 2026
  • Exposure window: ~30 years

PrintDemon (Windows):

  • Vulnerable code shipped: 1996
  • Public disclosure: 2020
  • Microsoft patch: May 2020
  • Exposure window: 24 years

Which Controls Failed or Were Missing

1. Dependency inventory and lifecycle tracking

Your team likely doesn't maintain a complete inventory of third-party libraries with installation dates and last-audit timestamps. Without this baseline, you can't prioritize which legacy components need immediate review.

The libpng case shows what happens when libraries age out of active scrutiny. If you're still linking against code written before your current developers joined the company, you're carrying significant risk.

2. Automated code analysis at scale

Manual code review doesn't scale to millions of lines of legacy code. Both vulnerabilities sat in codebases that received regular security attention, yet traditional tools missed them.

Static analysis tools from the early 2000s weren't designed to detect today's vulnerability patterns. If your scanning pipeline hasn't been updated in five years, you're looking for 2019 vulnerabilities in 2025 code.

3. Regression testing for security controls

Security testing often focuses on new features. Legacy code paths, especially in libraries like libpng or OS subsystems like Windows printing, receive minimal attention once they're "stable."

Neither vulnerability had test cases that would have caught the flaw. Your CI/CD pipeline probably doesn't include security regression tests for code older than your current sprint.

What the Relevant Standards Require

PCI DSS v4.0.1 Requirement 6.3.2 mandates maintaining an inventory of bespoke and custom software and third-party components. This isn't optional for payment environments, but the principle applies everywhere: you can't secure what you can't enumerate.

ISO/IEC 27001:2022 Control 8.31 implies you're testing security controls before production deployment. If you're not running security scans against legacy code, your production environment becomes your testing ground.

NIST 800-53 Rev 5 Control SA-11 requires security testing during development. For legacy systems, "development" includes maintenance patches and dependency updates. If you're not scanning before updating a 15-year-old library, you're skipping required controls.

OWASP ASVS v4.0.3 Level 2 requires verification that all components are up to date and that you've removed unnecessary features. A 30-year-old vulnerability means you failed both checks.

Lessons and Action Items for Your Team

Create a dependency age report

Run npm audit, pip-audit, or equivalent tools, then add a custom field: installation date. Sort by age, not just severity. Anything over five years old deserves a fresh security review regardless of what your scanner says.

Build a simple spreadsheet: library name, version, first-use date, last security review date, business criticality. Update it quarterly. If you can't fill in "last security review date" for a component, that's your priority list.

Implement AI-assisted code scanning for legacy systems

Traditional tools use pattern matching against known vulnerability signatures. Modern AI-based tools can identify suspicious code patterns even without exact CVE matches.

You don't need to replace your existing scanner. Run AI-assisted analysis as a supplementary pass on code older than three years. Review the findings manually, AI tools generate false positives, but they also catch patterns that signature-based tools miss.

Start with your authentication, cryptography, and input validation code. These are the areas where old threat model assumptions no longer hold.

Establish a legacy code audit rotation

Pick one legacy component per quarter for deep review. Don't wait for a vulnerability disclosure to trigger the audit.

Your rotation criteria:

  • Age (prioritize code over 10 years old)
  • Privilege level (kernel code, authentication systems)
  • External exposure (anything parsing user input)
  • Patch frequency (if it hasn't been updated in 3+ years, audit it)

Document your findings even if you don't find vulnerabilities. Knowing that you reviewed libpng in Q2 2025 and found nothing is valuable information for your next audit cycle.

Test security controls in legacy code paths

Add security regression tests for your oldest code. If you have a printing subsystem from 2005, write tests that verify it handles malformed input correctly. If you're using an image processing library from 2010, test it against fuzzing inputs.

These tests don't need to be comprehensive, you're looking for obvious failures in code that hasn't been exercised in years. Run them monthly, not just when you push updates.

Update your patch management SLA for legacy components

Your current SLA probably says "patch critical vulnerabilities within 30 days." Add a clause: "Review and audit dependencies older than 5 years within 90 days of this policy taking effect, then annually thereafter."

This gives you a compliance hook to justify the time investment. When someone asks why you're auditing a library that hasn't had a CVE in a decade, point to your policy.

The libpng and PrintDemon cases prove that absence of known vulnerabilities doesn't mean absence of vulnerabilities. It means absence of looking hard enough.

Topics:Incident

You Might Also Like