CVE-2026-73067 Overview
CVE-2026-73067 is a heap out-of-bounds read vulnerability [CWE-125] in the Tesseract open source OCR engine. Versions prior to 5.5.3 fail to validate the structure of .traineddata model files loaded through TessBaseAPI::Init. A crafted model with an unterminated forward-edge run causes SquishedDawg::read_squished_dawg in src/dict/dawg.cpp to accept malformed data. Subsequent processing invokes num_forward_edges(0) and last_edge in src/dict/dawg.h, which reads beyond the edges_ buffer. The result is a heap out-of-bounds read and process crash before any image processing begins. The issue is fixed in Tesseract 5.5.3.
Critical Impact
A malicious .traineddata file loaded by a Tesseract-based application triggers a heap out-of-bounds read and reliable process crash, denying OCR service before image processing starts.
Affected Products
- Tesseract OCR engine versions prior to 5.5.3
- Applications and services embedding libtesseract that load user-supplied .traineddata models
- Downstream distributions packaging Tesseract 5.x before the 5.5.3 update
Discovery Timeline
- 2026-08-11 - CVE-2026-73067 published to NVD
- 2026-08-11 - Last updated in NVD database
Technical Details for CVE-2026-73067
Vulnerability Analysis
The flaw resides in Tesseract's Directed Acyclic Word Graph (DAWG) deserialization path. When TessBaseAPI::Init loads a language model, SquishedDawg::read_squished_dawg reads an edge table from the .traineddata container. The pre-patch code does not verify that the declared num_edges_ matches the bytes remaining in the file component, nor does it validate that forward-edge runs are terminated by a last_edge marker.
Once the malformed edge table is accepted, SquishedDawg::Load calls num_forward_edges(0), which walks edges using last_edge from src/dict/dawg.h. Because no terminator exists, the walk advances past the end of the heap-allocated edges_ array. This constitutes an out-of-bounds read of adjacent heap memory and typically results in a segmentation fault before OCR begins.
Root Cause
The root cause is missing input validation during deserialization of untrusted .traineddata payloads. The loader trusts the on-disk num_edges_ count and the structural invariant that every forward-edge run terminates with a last_edge flag. A crafted model breaks both assumptions, allowing the graph traversal helpers to dereference memory outside the allocated edge buffer.
Attack Vector
Exploitation requires an attacker to supply a malicious .traineddata file that is loaded by a Tesseract-based application. The attack vector is local and requires user interaction, since the victim application must be pointed at the crafted model. Impact is limited to availability: the target process crashes. No code execution or information disclosure is described in the advisory.
// Patch: src/dict/dawg.cpp — reject malformed edge tables and validate DAWG structure
tprintf("Empty dawg: num_edges is 0\n");
return false;
}
+ // Reject if the declared edge count exceeds the remaining component bytes.
+ if (num_edges_ > file->RemainingBytes() / sizeof(EDGE_RECORD)) {
+ tprintf("Dawg num_edges %u exceeds remaining data\n", num_edges_);
+ return false;
+ }
Dawg::init(unicharset_size);
edges_ = new EDGE_RECORD[num_edges_];
if (!file->DeSerialize(&edges_[0], num_edges_)) {
return false;
}
+ // Validate the loaded edge structure: check that next_node values are in
+ // bounds and that forward edge runs are properly terminated.
+ for (uint32_t i = 0; i < num_edges_; ++i) {
+ if (edges_[i] == next_node_mask_) {
+ continue; // Empty slot.
+ }
+ NODE_REF next = next_node_from_edge_rec(edges_[i]);
+ if (next != 0 && static_cast<uint32_t>(next) >= num_edges_) {
+ tprintf("Dawg edge %u has out-of-bounds next_node\n", i);
+ return false;
+ }
+ if (forward_edge(i)) {
+ uint32_t j = i;
+ bool terminated = false;
+ do {
+ if (last_edge(j)) {
// Source: https://github.com/tesseract-ocr/tesseract/commit/55287a94b8044c05ce3fd10f5aca6ebbd238e518
The patch introduces a RemainingBytes() helper on the deserialization stream and rejects any edge count larger than the remaining component. It also iterates the loaded edges to confirm that next_node values are within bounds and that every forward-edge run terminates. A related commit hardens .traineddata font deserialization by rejecting oversized font names and widening init_spacing to uint32_t.
Detection Methods for CVE-2026-73067
Indicators of Compromise
- Unexpected .traineddata files placed under TESSDATA_PREFIX or an application's model directory from an untrusted source
- Repeated segmentation faults or SIGSEGV core dumps from processes linking libtesseract shortly after TessBaseAPI::Init calls
- Log entries containing Empty dawg: num_edges is 0 or, on patched builds, Dawg num_edges ... exceeds remaining data and Dawg edge ... has out-of-bounds next_node
Detection Strategies
- Inventory hosts that ship or embed Tesseract and identify versions earlier than 5.5.3 using package managers or binary version strings
- Alert on writes to .traineddata files outside of package-manager or approved deployment paths
- Monitor for OCR worker processes exiting abnormally in tight succession, which suggests malformed model delivery
Monitoring Recommendations
- Enable core dump collection on Tesseract-consuming services so out-of-bounds reads can be triaged against this CVE
- Log the SHA-256 of every .traineddata file loaded and compare against the hashes published on the Tesseract release page and tessdata repositories
- Track process crash telemetry from endpoints and container workloads that run OCR pipelines, and correlate crashes with recent model file changes
How to Mitigate CVE-2026-73067
Immediate Actions Required
- Upgrade Tesseract to version 5.5.3 or later on all systems, including container images and CI runners
- Restrict .traineddata sources to trusted, signed model repositories and remove any user-writable model directories
- Audit application code paths that pass user-controlled filesystem paths to TessBaseAPI::Init and enforce an allow-list of model files
Patch Information
The fix is delivered in Tesseract Release 5.5.3. The relevant changes are commit 55287a94, which validates DAWG edge structure, and commit 82727cc1, which hardens .traineddata font deserialization. Full context is available in the GitHub Security Advisory GHSA-x3vq-7rr7-5x3h, Issue #4580, and Pull Request #4581.
Workarounds
- Run Tesseract-based OCR workers in isolated sandboxes or containers with restricted filesystem access so a crash cannot affect neighboring services
- Validate the origin and integrity of every .traineddata file before deployment by comparing checksums against the upstream tessdata repositories
- Disable dynamic loading of user-supplied models and ship a fixed, vetted set of language files with the application
# Verify installed Tesseract version and identify vulnerable hosts
tesseract --version
# Example: pin Tesseract >= 5.5.3 in a Debian/Ubuntu build
apt-get install -y --no-install-recommends 'tesseract-ocr>=5.5.3'
# Restrict traineddata directory to root ownership and read-only for services
chown -R root:root "$TESSDATA_PREFIX"
chmod -R a-w,a+rX "$TESSDATA_PREFIX"
# Verify integrity of a traineddata file against a known-good hash
sha256sum "$TESSDATA_PREFIX/eng.traineddata"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

