CVE-2026-28211
Code execution in NVDA Dev & Test Toolbox via a malicious log file.
- CVSS 7.8
- CWE-943
- Input Validation and Sanitization
- Local
The NVDA Dev & Test Toolbox is an NVDA add-on for gathering tools to help NVDA development and testing. A vulnerability exists in versions 2.0 through 8.0 in the Log Reader feature of this add-on. A maliciously crafted log file can lead to arbitrary code execution when a user reads it with log reader commands. The log reading command process speech log entries in an unsafe manner. Python expressions embedded in the log may be evaluated when when speech entries are read with log reading commands. An attacker can exploit this by convincing a user to open a malicious crafted log file and to analyze it using the log reading commands. When the log is read, attacker-controlled code may execute with the privileges of the current user. This issue does not require elevated privileges and relies solely on user interaction (opening the log file). Version 9.0 contains a fix for the issue. As a workaround, avoid using log reading commands, or at least, commands to move to next/previous log message (any message or commands for each type of message). For more security, one may disable their gestures in the input gesture dialog.
- CWE
- CWE-943
- CVSS base score
- 7.8
- Published
- 2026-02-26
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Serialization Issues
- Category
- Input Validation and Sanitization
- Subcategory
- Command Injection
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Fixed by upgrading
- Yes
Solution
Upgrade the NVDA Dev & Test Toolbox add-on to version 9.0.
Vulnerable code sample
import os
import sys
# This code is a conceptual representation based on the CVE description.
# It simulates the vulnerable logic of the NVDA Dev & Test Toolbox add-on
# versions 2.0 through 8.0.
# The vulnerability lies in the use of `eval()` on untrusted log file content.
class UnsafeLogReader:
"""
A simulated class representing the vulnerable log reader feature.
It reads log entries and processes them in an insecure manner.
"""
def __init__(self, log_content):
"""
Initializes the reader with log content. In a real scenario,
this would read from a file on disk.
"""
self.log_entries = self._parse_log_for_speech(log_content)
self.current_index = -1
def _parse_log_for_speech(self, content):
"""
A simplified parser that extracts the arguments of 'speech.speak'
commands from the log.
"""
parsed_entries = []
for line in content.splitlines():
if 'speech.speak' in line:
try:
# Extracts the content within the parentheses of speech.speak(...)
payload = line.split('speech.speak', 1)[1]
if payload.startswith('(') and payload.endswith(')'):
parsed_entries.append(payload)
except IndexError:
# Ignore lines that are malformed
continue
return parsed_entries
def _process_speech_entry(self, entry_string):
"""
THE CORE VULNERABILITY.
The log entry, which is just a string from an external file,
is passed to `eval()`. The original developer likely intended this
to reconstruct Python objects (e.g., tuples, lists) from their
string representation in the log. However, it executes any
arbitrary Python expression embedded in the string.
"""
print(f"[*] Processing entry via eval(): {entry_string}")
try:
# The unsafe evaluation of the log entry string.
evaluated_data = eval(entry_string, {"__builtins__": __builtins__})
# In the real add-on, this data would be used to generate speech.
# We simulate this by printing the processed data.
print(f"[+] Successfully evaluated data: {evaluated_data}")
except Exception as e:
print(f"[!] An error occurred during evaluation: {e}")
print("-" * 20)
def read_next_log_message(self):
"""
Simulates the user command to move to the next log message.
This triggers the processing of the entry.
"""
self.current_index += 1
if self.current_index < len(self.log_entries):
entry_to_process = self.log_entries[self.current_index]
self._process_speech_entry(entry_to_process)
else:
print("[*] Reached the end of the log file.")
# --- Demonstration of the exploit ---
if __name__ == '__main__':
# 1. An attacker crafts a malicious log file.
# The string below represents the content of this file.
malicious_log_file_content = """
INFO: NVDA main startup
DEBUG: Initializing core
# A normal, benign log entry for speech
IO - speech.speak(('This is a normal log message.',))
# A maliciously crafted log entry
# Instead of a simple string tuple, it contains an OS command to be executed.
IO - speech.speak((__import__('os').system('echo ">>> PWNED: Arbitrary code was executed <<<"'),))
DEBUG: Core initialization complete
"""
# 2. The user opens this malicious log file with the vulnerable tool.
print("--- Starting Vulnerable Log Reader Simulation ---")
log_reader = UnsafeLogReader(malicious_log_file_content)
# 3. The user interacts with the tool, triggering the vulnerability.
print("\n[USER ACTION] Reading first log message...")
log_reader.read_next_log_message()
print("\n[USER ACTION] Reading second (malicious) log message...")
log_reader.read_next_log_message()
print("\n--- Simulation Complete ---")Patched code sample
import ast
def fixed_process_log_entry(entry_string):
"""
Safely processes a log entry string, representing the fix for CVE-2026-28211.
The original vulnerability was caused by unsafely evaluating log entries,
which could contain malicious Python expressions, using a function like `eval()`.
This allowed for arbitrary code execution.
This corrected function uses `ast.literal_eval()` as a secure replacement.
`ast.literal_eval()` can only parse and evaluate Python literals (e.g.,
strings, numbers, tuples, lists, dicts, booleans, None). It explicitly
prevents the execution of arbitrary code, function calls (like `__import__`),
or complex expressions, thereby mitigating the vulnerability.
Args:
entry_string (str): A line from a log file, which is expected to be a
string representation of a Python literal.
Returns:
The safely parsed Python object, or None if parsing fails due to a
non-literal or malformed expression.
"""
try:
# SAFE: `ast.literal_eval` will safely parse the string into a Python
# literal. It will raise a ValueError or other exception if the string
# contains code or expressions, preventing execution.
# For a malicious input like "(__import__('os').system('calc'),)", this
# will fail instead of executing the command.
safely_parsed_data = ast.literal_eval(entry_string)
# The data is now safe to be processed further by the application.
return safely_parsed_data
except (ValueError, TypeError, SyntaxError, MemoryError, RecursionError):
# If the entry string is not a valid literal (e.g., it contains code),
# an exception is caught, and the malicious payload is neutralized.
# The application can then handle this by treating it as a plain
# string or logging an error, without executing it.
return NonePayload
INFO - synthDriverHandler.speak (12:34:56.789) - MainThread (1234): Speaking: __import__('os').system('calc')
Cite this entry
@misc{vaitp:cve202628211,
title = {{Code execution in NVDA Dev & Test Toolbox via a malicious log file.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-28211},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-28211/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
