Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-45729 — ThorVG NULL pointer dereference via malformed SVG — AFL++ fuzzing writeup | Kitploit
Tools/GitHubGitHub/yeahhbean/cve-2026-45729
Embedded Systems SecurityIoT SecurityVulnerability AnalysisExploitationFuzzingBinary Analysis
GitHubyeahhbean/cve-2026-45729

CVE-2026-45729

ThorVG NULL pointer dereference via malformed SVG — AFL++ fuzzing writeup

View Repository
131 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-45729 — ThorVG NULL Pointer Dereference via Malformed SVG

Severity: CVSS 4.3 (Medium) — CWE-476
Advisory: GHSA-f863-8ghq-7h64
Fixed: ThorVG v1.0.5
Status: Patched / Disclosed


Summary

ThorVG's SVG parser dereferences a pointer that is never initialized when it encounters a truncated child element tag inside a root <svg> node. The bug is reachable through the normal rendering path (tvg::Picture::load → parse → render) and can be triggered with a 6-byte input.

The worst-case impact on standard Linux is a process crash (DoS) — mmap_min_addr prevents mapping the NULL page, so the fault is not directly exploitable for code execution in that environment. On MMU-less targets where ThorVG is also used (Tizen, LVGL-based firmware) the exploitability picture is different and warrants a closer look.


Target selection rationale

ThorVG is a cross-platform vector graphics engine written in C++17. It is the default SVG/Lottie renderer in Samsung Tizen OS, is bundled in LVGL (widely used in embedded/IoT UI), and is distributed as a standalone library on multiple platforms.

The library processes untrusted SVG/JSON input and is often exposed in contexts without privilege separation. Parser code in graphics libraries has historically been a reliable source of memory safety bugs — ThorVG is actively developed and at the time of this research had no recorded fuzzing coverage in public bug trackers.


Fuzzing setup

Harness

The harness wraps ThorVG's in-memory load API so AFL++ can drive the parser directly without disk I/O.

root@kitploit:~
// fuzz_thorvg.cpp
#include <cstdint>
#include <cstring>
#include <thorvg.h>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size == 0) return 0;

    tvg::Initializer::init(tvg::CanvasEngine::Sw, 0);

    auto canvas = tvg::SwCanvas::gen();
    uint32_t buf[64 * 64] = {};
    canvas->target(buf, 64, 64, 64, tvg::SwCanvas::ARGB8888);

    auto picture = tvg::Picture::gen();
    // Load SVG from raw bytes; mimeType hint "svg" triggers the SVG parser path
    if (picture->load(reinterpret_cast<const char*>(data), size, "svg", false)
            == tvg::Result::Success) {
        canvas->push(tvg::cast(picture));
        canvas->draw();
        canvas->sync();
    }

    tvg::Initializer::term(tvg::CanvasEngine::Sw);
    return 0;
}

Build with ASAN + coverage instrumentation:

root@kitploit:~
clang++ -std=c++17 -fsanitize=address,undefined -fprofile-instr-generate \
    -fcoverage-mapping -O1 -g \
    fuzz_thorvg.cpp -o fuzz_thorvg \
    $(pkg-config --cflags --libs thorvg)

Seed corpus

Starting from scratch with random bytes performs poorly on format-sensitive parsers. I seeded the corpus with a set of structurally valid minimal SVG files covering:

  • Empty SVG (<svg xmlns="..."/>)
  • SVG with basic shapes (<rect>, <circle>, <path>)
  • SVG with a nested <g> group
  • SVG with a <use> xlink reference
  • A small Lottie/JSON animation (ThorVG also handles this format)

Structure-aware seeds cut the time to first interesting paths from hours to under 20 minutes in my environment.

AFL++ flags

root@kitploit:~
AFL_AUTORESUME=1 afl-fuzz \
    -i corpus/ \
    -o findings/ \
    -x svg.dict \
    -m none \
    -- ./fuzz_thorvg @@

-x svg.dict — AFL++ token dictionary with SVG keywords to help mutate toward valid tag names.
-m none — ASAN shadow memory requires disabling AFL++'s memory limit.


Crash discovery

AFL++ produced a crash after approximately 3 hours of single-core fuzzing. The initial crashing input was ~180 bytes. The ASAN output:

root@kitploit:~
==pid==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x... ...)
SEGV on address NULL
#0 in tvg::SvgParser::_parseStyle(...)
#1 in tvg::SvgParser::_createElement(...)
#2 in tvg::SvgParser::parse(...)
#3 in tvg::SvgLoader::read()
...

The fault is a read through an uninitialized (NULL) SvgNode* pointer inside _parseStyle. The pointer is expected to be set by _createElement when it processes a child element, but a truncated tag name causes the element to be skipped without the pointer being assigned, and _parseStyle proceeds to dereference it regardless.


Minimization

Minimized with afl-tmin, then manual pruning:

root@kitploit:~
afl-tmin -i findings/crashes/id:000000 -o min -- ./fuzz_thorvg @@

After afl-tmin the input was 14 bytes. Manual inspection of the parse path showed only the first 6 bytes were consumed before the fault:

root@kitploit:~
<svg><

<svg> opens the root node. < starts a child element tag. The parser reads the tag name, gets an empty string (the input ends immediately after <), skips element creation, and falls through into _parseStyle with the node pointer still NULL.

Confirm the 6-byte trigger reproduces:

root@kitploit:~
printf '<svg><' | ./fuzz_thorvg /dev/stdin
# or
echo -n '<svg><' > poc.svg && ./fuzz_thorvg poc.svg

Root cause

root@kitploit:~
src/loaders/svg/tvgSvgParser.cpp

Simplified pseudocode of the vulnerable flow:

root@kitploit:~
// _createElement returns nullptr when tag name is empty
SvgNode* node = _createElement(tagName);   // tagName == "" → returns nullptr

// No NULL check before passing into style parser
_parseStyle(node, attributes);             // ← dereferences node->style at offset 0x18

The fix in v1.0.5 adds an early return in the element dispatch loop when _createElement returns nullptr, before any attribute/style processing is attempted.


Exploitability analysis

Standard Linux (CVSS 4.3 / Medium)

/proc/sys/vm/mmap_min_addr is typically set to 65536 on modern distros. The NULL page is not mapped, so the CPU raises a SIGSEGV that the kernel converts to a signal to the process — result is a crash (DoS). No controlled write, no PC control, not directly exploitable for code execution.

Embedded / MMU-less targets

ThorVG is a first-class citizen in Tizen (Samsung IoT/wearable OS) and is integrated into LVGL, which runs on microcontrollers and systems without an MMU.

On MMU-less systems there is no memory protection and mmap_min_addr does not apply. If the NULL page is mapped (which is common in bare-metal embedded environments), a NULL pointer dereference can potentially point into attacker-controlled memory. Whether this is reachable in a real attack depends on the attack surface — ThorVG on a Tizen device may parse SVG from untrusted network sources or user-supplied content.

This context is what justifies responsible disclosure even for a CVSS Medium finding.


Disclosure timeline


Patch diff (summary)

The patch adds a NULL guard in the SVG element dispatch loop:

root@kitploit:~
// before (vulnerable)
SvgNode* node = _createElement(tag);
_parseStyle(node, attrs);   // unconditional

// after (v1.0.5)
SvgNode* node = _createElement(tag);
if (!node) continue;        // skip if element was not created
_parseStyle(node, attrs);

Full diff: ThorVG v1.0.5 release


Reproduction (safe, local only)

root@kitploit:~
# build from source with ASAN
git clone https://github.com/thorvg/thorvg && cd thorvg
git checkout <vulnerable-tag-before-v1.0.5>
meson setup build -Db_sanitize=address && ninja -C build

# compile harness against the built library
clang++ -std=c++17 -fsanitize=address -O1 -g \
    fuzz_thorvg.cpp -o fuzz_thorvg \
    -Ibuild/src/include -Lbuild/src -lthorvg

# trigger
printf '<svg><' | ./fuzz_thorvg /dev/stdin

Expected output: ASAN report with SEGV on unknown address 0x000000000000 in tvg::SvgParser::_parseStyle.


References

  • GHSA-f863-8ghq-7h64
  • ThorVG project
  • CWE-476: NULL Pointer Dereference
  • AFL++ documentation

Found by yeahhbean (이예빈) via AFL++ coverage-guided fuzzing with structure-aware SVG seed corpus.

Download Tool
DateEvent
2026-xx-xxCrash discovered via AFL++
2026-xx-xxRoot cause confirmed under ASAN; 6-byte POC produced
2026-xx-xxPrivate report sent to ThorVG maintainer (hermet) via GitHub Security Advisory
2026-xx-xxMaintainer acknowledged and opened private fork
2026-xx-xxPatch merged into v1.0.5
2026-xx-xxGHSA-f863-8ghq-7h64 published; CVE-2026-45729 assigned