Skip to content

[BUG] Severe Memory & Data Leak: Unmanaged static ThreadLocal in ScenarioEngine #2745

@QiuYucheng2003

Description

@QiuYucheng2003

Description
Summary:
In com.intuit.karate.core.ScenarioEngine, the current engine instance is stored in a static final ThreadLocal. However, the cleanup mechanism (remove()) is not enforced internally via a try-finally block within the class's lifecycle. It relies entirely on external callers to clean it up.

Root Cause:
If an unhandled exception occurs during execution, or if Karate is invoked via a custom runner/thread-pool that misses the cleanup step, the ScenarioEngine instance remains attached to the thread indefinitely.

Impact (Critical):

  1. Memory Leak: ScenarioEngine holds heavy objects like Driver (Selenium/Playwright) and JsEngine (GraalVM). In a long-running environment (e.g., Synthetic Monitoring), this leads to OutOfMemoryError.

  2. Data/Credential Leak: The engine holds vars (variables), which often contain secrets, tokens, or user credentials. If the thread is reused (common in web containers or CI runners), a subsequent task could potentially access sensitive data from the previous run.

Location
File: karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java

  1. Definition (Line 125):
    private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
  2. Risky Cleanup (Line 135):
    protected static void remove() {
    THREAD_LOCAL.remove();
    }
    // There is no guarantee this is called if the runner crashes.

To Reproduce

  1. Run Karate scenarios using a custom thread pool or within a Servlet container.

  2. Induce a runtime exception that bypasses the standard runner's cleanup logic.

  3. Inspect the Thread Dump: The worker thread will still hold a strong reference to ScenarioEngine (and all its variables/drivers).

Expected Behavior
The lifecycle of ScenarioEngine should be strictly managed.
Recommendation: Wrap the execution logic in a defensive try-finally block that guarantees THREAD_LOCAL.remove() is called, regardless of success or failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions