CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-24738

Passport to Purgatory: Infinite Loops in gmrtd

Alon Barad
Alon Barad
Software Engineer

Jan 27, 2026·6 min read·31 visits

Executive Summary (TL;DR)

The `gmrtd` library, used to read ePassports, blindly trusts the length declared by the NFC chip. By presenting a chip that claims to hold 4GB of data, an attacker can force the reader into an infinite read loop, causing CPU exhaustion and an eventual Out-of-Memory (OOM) crash.

A Denial of Service (DoS) vulnerability in the gmrtd Go library allows a malicious NFC chip to crash reading applications by advertising a fake, massive file size (4GB+), leading to memory exhaustion.

The Hook: When the Passport Attacks You

We usually think of NFC security in one direction: a malicious reader skimming your credit card or passport in a crowded subway. We worry about shielding sleeves and cryptograms. But rarely do we consider the inverse scenario: what if the passport itself is the weapon?

Enter gmrtd, a Go library designed to handle the heavy lifting of parsing Machine Readable Travel Documents (MRTDs) via the ISO7816 protocol. It implements the complex dance of APDU commands required to authenticate and read data groups (DGs) from the chip—like your face photo or biometric fingerprints.

In a perfect world, hardware adheres to spec. In the real world, hardware lies. CVE-2026-24738 is a classic case of "implicit trust." The library assumes that if an NFC chip says, "I have a file here, and it is 4 gigabytes long," the chip is telling the truth. This assumption turns every border control kiosk or ID-verification mobile app using this library into a sitting duck for a simple resource exhaustion attack.

The Flaw: Trusting the Length Byte

The vulnerability lies in how gmrtd handles BER-TLV (Basic Encoding Rules - Tag-Length-Value) encoded data. When you read a file from an ePassport, the first thing you get is a header. This header tells you what the data is (Tag) and how big it is (Length).

In the smart card world, lengths can be encoded in "short form" (one byte) or "long form." Long form allows you to specify massive sizes by using a prefix like 0x84, followed by four bytes representing the size. This theoretically allows a file size up to 4GB (0xFFFFFFFF).

The flaw is embarrassingly simple: gmrtd parsed this length and immediately committed to reading that many bytes. It didn't ask, "Does a 4GB photo make sense on a low-power smart card?" It didn't ask, "Do I even have enough RAM to hold this?" It just shrugged and entered a loop.

This is a logic bug class known as Uncontrolled Resource Consumption (CWE-400). By failing to validate the upper bound of the length field against a sanity limit (like the max size of an ISO7816 file or available memory), the code voluntarily enters a death spiral.

The Code: The Smoking Gun

Let's look at the crime scene in iso7816/nfc_session.go. The ReadFile function is responsible for fetching the Data Group. Here is the logic before the fix:

func (nfc *NfcSession) ReadFile(fileId uint16) (fileData []byte, err error) {
    // [1] Read the header from the chip
    fileHeader, err := nfc.ReadBinary(0, 4) 
    
    // [2] Parse the Tag and Length. 
    // tmpTlvLength comes directly from the malicious chip.
    tmpTag, tmpTlvLength, tmpBuf, err := tlv.ParseTagAndLength(fileHeader)
    
    // [3] Set the target. No validation occurs here.
    totalBytes = int(tmpTlvLength)
    totalBytes += 4 - tmpBuf.Len()
 
    // [4] The Loop of Doom
    if fileBuf.Len() < totalBytes {
        for {
            // Calculate next chunk size
            bytesToRead := min(maxReadAmount, totalBytes-fileBuf.Len())
            
            // Read the chunk
            tmpData, err := nfc.ReadBinaryFromOffset(fileBuf.Len(), bytesToRead)
            
            // Append forever until OOM or totalBytes is reached
            fileBuf.Write(tmpData)
        }
    }
}

The code at [3] is the fatal error. It takes tmpTlvLength (which could be 4,294,967,295) and sets it as the goalpost. The for loop at [4] will then execute millions of times, issuing READ BINARY commands and appending the results to a byte slice until the Go runtime panics with an Out of Memory error or the CPU melts.

The Exploit: The Infinite Passport

To exploit this, you don't need a supercomputer. You need a $150 Flipper Zero or a rooted Android phone running a card emulation app. The goal is to emulate an ePassport that looks normal during the initial handshake but becomes a monster when the reader asks for data.

Here is the attack chain:

  1. Handshake: The attacker presents the emulated device. The reader (victim) performs the standard ISO7816 selection and authentication.
  2. The Trap: The reader requests DG2 (the facial image). This is standard procedure for almost all ID verification flows.
  3. The Trigger: The emulated chip responds to the first READ BINARY command with a valid Tag (0x61) but a weaponized Length: 0x84 0xFF 0xFF 0xFF 0xFF (4GB).
  4. The Stall: The reader sees the length and starts requesting chunks of 256 bytes. The attacker's emulator simply replies with 256 bytes of garbage (zeros) and a success status word (0x90 0x00) for every request.

The victim application hangs immediately. If the application is single-threaded or the reading happens on the main UI thread, the interface freezes. Eventually, the operating system kills the process for consuming too much memory.

The Fix: Trust Nobody

The remediation, applied in v0.17.2, is a lesson in defensive programming. The maintainers implemented hard limits on what the library is willing to accept from the external world. They realized that a passport photo is never going to be 4GB. In fact, it's rarely going to be larger than 30-40KB.

The patch introduces two key constraints in iso7816/nfc_session.go:

  1. Max TLV Length Cap: A constant READ_FILE_MAX_TLV_LENGTH set to 65,535 bytes (64KB). If the chip declares a size larger than this, the library immediately aborts with an error.
  2. Max Chunk Count: A constant READ_FILE_MAX_CHUNKS set to 1000. This prevents a "slow loris" style attack where the chip returns valid total lengths but sends data 1 byte at a time to waste CPU cycles.

Here is the diff for the fix:

// The Fix: Sanity Checks
if tmpTlvLength > nfc.readFileMaxTlvLength {
    return nil, fmt.Errorf("[ReadFile] TLV length exceeds permitted maximum")
}
 
// Inside the loop
if chunkCnt >= nfc.readFileMaxChunks {
    return nil, fmt.Errorf("[ReadFile] Max chunks reached")
}

This turns an OOM crash into a graceful error message: "[ReadFile] TLV length exceeds permitted maximum". The application survives, logs the error, and the attacker is left standing there looking silly.

Official Patches

gmrtdCommit 54469a9: Fix ReadFile vulnerability

Fix Analysis (1)

Technical Appendix

CVSS Score
4.6/ 10
CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Border Control Kiosks using Go-based verificationMobile Identity Verification Apps (Android/iOS backends)Electronic ID (eID) readersAny Go software using `gmrtd` to interact with smart cards

Affected Versions Detail

Product
Affected Versions
Fixed Version
gmrtd
gmrtd
< 0.17.20.17.2
AttributeDetail
CWE IDCWE-400 (Uncontrolled Resource Consumption)
Attack VectorPhysical (NFC)
CVSS4.6 (Medium)
ImpactDenial of Service (DoS)
Patchv0.17.2
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.004Endpoint Denial of Service: Application or System Exploitation
Impact
CWE-400
Uncontrolled Resource Consumption

The software does not properly restrict the size or amount of resources that are requested or consumed, which can be used to consume all available resources.

Known Exploits & Detection

GitHubPoC included in the fix commit test cases (MockTransceiverHugeLength)

Vulnerability Timeline

Vulnerability discovered and patched
2026-01-26
Release v0.17.2 published
2026-01-26
CVE-2026-24738 assigned
2026-01-27

References & Sources

  • [1]GHSA Advisory
  • [2]gmrtd Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•1 day ago•GHSA-7PPR-R889-MCF2
7.5

GHSA-7PPR-R889-MCF2: Unbounded WebSocket Message Aggregation in http4s-blaze-server leads to Denial of Service

An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.

Alon Barad
Alon Barad
7 views•5 min read
•2 days ago•GHSA-95CV-R8X4-VH75
7.6

GHSA-95cv-r8x4-vh75: Path Traversal Vulnerability in OpenList Batch Rename Handler

A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.

Amit Schendel
Amit Schendel
8 views•7 min read
•2 days ago•GHSA-P6PH-3JX2-3337
4.3

GHSA-P6PH-3JX2-3337: Horizontal Privilege Escalation and Metadata Information Disclosure via Bleve Search in OpenList

OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.

Amit Schendel
Amit Schendel
8 views•5 min read
•2 days ago•GHSA-86CX-WWF4-PHQ4
6.5

GHSA-86cx-wwf4-phq4: Path Prefix Confusion Authorization Bypass in OpenList

An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.

Amit Schendel
Amit Schendel
7 views•6 min read
•2 days ago•CVE-2026-16584
7.0

CVE-2026-16584: Security Policy Bypass in AWS API MCP Server via Startup Initialization Failure

A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.

Amit Schendel
Amit Schendel
12 views•7 min read
•2 days ago•GHSA-6V4M-FW66-8R4X
6.5

GHSA-6V4M-FW66-8R4X: Path Disclosure and Shell Expansion Bypass in Shescape

An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.

Alon Barad
Alon Barad
6 views•7 min read