Back to Blog
high SEVERITY8 min read

ReDoS in Nushell's TUI: When Search Input Freezes Your Terminal

A high-severity Regular Expression Denial of Service (ReDoS) vulnerability was discovered and patched in Nushell's interactive TUI explorer, where unvalidated user keystrokes could be passed directly into regex compilation, allowing adversarial inputs to consume 100% CPU and freeze the interface. This fix adds proper input validation and length limits to the search input handler, preventing catastrophic backtracking attacks. Understanding this vulnerability is essential for any developer buildin

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published May 20, 2026•Reviewed June 3, 2026

Answer Summary

Regular Expression Denial of Service (ReDoS) is a vulnerability where specially crafted input patterns cause regex engines to enter catastrophic backtracking, consuming excessive CPU and freezing applications. In Nushell's TUI explorer, the search input handler compiled user keystrokes directly into regex patterns without validation. The fix adds input length limits and validates search patterns before compilation, preventing adversarial inputs from triggering exponential regex matching behavior. CWE-1333 covers this vulnerability class.

Vulnerability at a Glance

cweCWE-1333
fixAdd input validation, length limits, and safe regex compilation with timeout protection
riskApplication freeze, 100% CPU consumption, denial of service
languageRust (Nushell)
root causeUnvalidated user input passed directly to regex compilation without length limits
vulnerabilityRegular Expression Denial of Service (ReDoS)

Introduction

Imagine typing a search query into your terminal explorer and watching your entire system grind to a halt — CPU pegged at 100%, the interface completely frozen, and no way out short of killing the process. That's the real-world consequence of a Regular Expression Denial of Service (ReDoS) vulnerability, and it's exactly what was lurking in Nushell's interactive TUI (Text User Interface) explorer.

This post breaks down the vulnerability discovered in crates/nu-explore/src/explore_config/tui.rs, explains how it could be exploited, and walks through the fix that was applied to protect users. Whether you're a Rust developer, a CLI tool maintainer, or simply someone who cares about writing robust software, this is a pattern worth understanding deeply.


The Vulnerability Explained

What Is ReDoS?

Regular Expression Denial of Service (ReDoS) is a class of vulnerability that exploits the way certain regex engines evaluate patterns. Most traditional regex engines use backtracking to find matches — when a path doesn't work, the engine backs up and tries another. For most inputs, this is fast. But certain combinations of patterns and inputs can cause the engine to explore an exponentially growing number of paths before concluding there's no match.

This is called catastrophic backtracking, and it can turn a single search query into an infinite loop.

The Vulnerable Code Path

The vulnerability existed in Nushell's TUI explorer at tui.rs:112. Here's the problematic flow:

User keystroke
     │
     ▼
handle_search_input()   ← tui.rs:112
     │
     ▼
apply_search_filter()   ← app.rs:194
     │
     ▼
Regex::new(user_input)  ← compiled without validation ⚠️

User keystrokes captured by handle_search_input() were passed directly to apply_search_filter() without:

  • ✗ Input sanitization or escaping
  • ✗ Length limits
  • ✗ Debouncing (rate limiting keystrokes)
  • ✗ Validation that the input forms a safe regex

How Could It Be Exploited?

An attacker (or even an unsuspecting user) could type a carefully crafted pattern into the TUI search box. Classic catastrophic backtracking patterns include:

# Catastrophic backtracking examples
(a+)+
(a|aa)+
([a-zA-Z]+)*
(a+)+$

When matched against a non-matching string like "aaaaaaaaaaaaaaaaaab", these patterns force the regex engine to explore an astronomical number of backtracking paths.

Example attack scenario:

# A user opens nu-explore and navigates to a large data table
# They type the following into the search box:
(a+)+zzzzzzzzzzzzzzzzzzzzz

# The regex engine begins evaluating this against every cell in the table
# CPU usage spikes to 100%
# The TUI freezes — no keyboard input is processed
# The user is forced to kill the terminal or reboot

Even without malicious intent, a user experimenting with regex syntax could accidentally trigger this. In a tool designed for exploring data interactively, a frozen interface is a critical failure.

Why Is This Rated High Severity?

  • Availability impact: The application becomes completely unresponsive
  • No authentication required: Any user of the tool can trigger it
  • Ease of exploitation: The payload is trivial to construct
  • No resource recovery: Without a timeout or kill mechanism, the process must be forcibly terminated
  • Data loss risk: Any unsaved state in the explorer session is lost when the process is killed

This maps to CWE-400: Uncontrolled Resource Consumption and is catalogued under the OWASP category of Denial of Service.


The Fix

The patch was applied in crates/nu-explore/src/explore_config/input.rs and addresses the vulnerability through a combination of defensive input handling strategies.

What Changed

Before: Unvalidated Input Flow

// tui.rs:112 (simplified representation of vulnerable pattern)
fn handle_search_input(&mut self, key: KeyEvent) {
    match key.code {
        KeyCode::Char(c) => {
            self.search_query.push(c);
            // Directly passed to filter — no validation!
            self.app.apply_search_filter(&self.search_query);
        }
        // ...
    }
}

// app.rs:194 (simplified)
fn apply_search_filter(&mut self, query: &str) {
    // Compiles user input directly as a regex ⚠️
    if let Ok(re) = Regex::new(query) {
        self.filter_data_with_regex(re);
    }
}

After: Validated, Length-Limited Input

// input.rs (patched)
const MAX_SEARCH_INPUT_LENGTH: usize = 128;

fn handle_search_input(&mut self, key: KeyEvent) {
    match key.code {
        KeyCode::Char(c) => {
            // Enforce length limit before appending
            if self.search_query.len() >= MAX_SEARCH_INPUT_LENGTH {
                return;
            }
            self.search_query.push(c);

            // Validate the regex before applying
            if let Some(safe_query) = validate_search_input(&self.search_query) {
                self.app.apply_search_filter(&safe_query);
            }
        }
        // ...
    }
}

fn validate_search_input(input: &str) -> Option<String> {
    // Reject inputs that are too long
    if input.len() > MAX_SEARCH_INPUT_LENGTH {
        return None;
    }

    // Attempt to compile — but with a complexity budget
    // or escape the input to treat it as a literal string
    // rather than a raw regex pattern
    Some(regex::escape(input))
}

Note: The exact implementation details may vary from the simplified representation above. The core principle — length limiting and input validation before regex compilation — is what matters.

How Does This Fix the Problem?

The patch applies defense in depth through multiple layers:

  1. Length limits: Capping input at 128 characters dramatically reduces the search space available to an attacker. Catastrophic backtracking patterns typically need room to grow — a hard length cap cuts them off at the knees.

  2. Input validation: By validating or escaping the input before passing it to the regex engine, the fix ensures that user input is treated as a literal search string rather than an arbitrary regex pattern. This is the safest default for a general-purpose search box.

  3. Separation of concerns: Moving validation logic into input.rs creates a clear boundary — input handling is now responsible for ensuring data is safe before it ever reaches the application logic layer.


Conclusion

The ReDoS vulnerability in Nushell's TUI explorer is a textbook example of how a seemingly innocuous feature — a search box — can become a denial-of-service vector when input isn't properly validated. The fix is elegant in its simplicity: enforce length limits, validate or escape input before it reaches the regex engine, and separate input handling from application logic.

Key Takeaways

  • 🔍 Treat all user input as untrusted, even in local, single-user tools
  • 📏 Enforce length limits early — at the point of input, not the point of use
  • 🛡️ Escape user input before using it as a regex pattern, unless regex mode is explicitly intended
  • ⏱️ Debounce live search to reduce unnecessary computation
  • 🧪 Test with adversarial inputs — include ReDoS patterns in your security test suite

Security vulnerabilities in developer tools deserve just as much attention as vulnerabilities in web applications. The developers who use these tools are often handling sensitive data, and a frozen or crashed tool at the wrong moment can have real consequences.

If you're maintaining a CLI tool or TUI application with search functionality, take 30 minutes today to audit your input handling. The fix is usually simple — the cost of not fixing it is not.


This vulnerability was identified and patched as part of automated security scanning by OrbisAI Security. Responsible disclosure and rapid patching are what keep the open-source ecosystem healthy.

Prevention and further reading

Related Articles

medium

path-to-regexp 0.1.12 DoS: Catastrophic Backtracking on Malformed URL

path-to-regexp version 0.1.12 contains a regular expression engine vulnerability where maliciously crafted URL parameters trigger exponential backtracking, causing CPU exhaustion and service unavailability. Upgrading to version 0.1.13 eliminates the vulnerable pattern from the parsing logic.

critical

CVE-2026-59873: node-tar 7.5.11 DoS via Crafted Gzip Bomb

node-tar versions 7.5.11 through 7.5.18 are vulnerable to a denial-of-service attack through maliciously crafted gzip archives that decompress to disproportionately large sizes. An attacker can exploit this to exhaust memory and CPU resources by submitting a small, highly compressed archive that expands beyond configured limits during extraction.

high

MapManager.get() Race Condition Duplicates API Requests

The MapManager's `get(mapUid, cache)` method used a check-then-act pattern that permitted multiple concurrent requests to pass the cache miss check simultaneously, triggering redundant API calls and risking cache corruption. The fix introduces a `_pending` promise map to deduplicate in-flight fetches for identical map UIDs.

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.