Safeguard
Application Security•

CWE-572 Call to Thread run() Instead of start() in Java

Calling run() on a Thread runs the work in the caller's thread. See why CWE-572 is a bug and how to fix it with start().

Safeguard Security Team
3 min read

CWE-572 is a Java mistake. A program calls a thread's run() method when it meant to call start(). The code runs in the caller's thread rather than in a new one.

MITRE says that in most cases a direct call to run() is a bug: the programmer intended to begin a new thread of control, but accidentally called run(), so the method executes in the caller's thread.

It looks harmless, since the work still happens. But the program is now sequential where it was meant to be concurrent.

How it happens

Thread.run() is an ordinary method. Thread.start() is what asks the JVM to create a new thread and call run() on it. The two names look close, and code compiles either way.

MITRE's example:

// Vulnerable: runs on the current thread
Thread thr = new Thread() {
    public void run() {
        ...
    }
};
thr.run();

Effects:

  • The caller blocks until the work finishes. A request handler that was meant to hand off slow work now makes the user wait.
  • If the work loops forever or waits on I/O, the calling thread hangs.
  • Code that relies on thread local state, timeouts or interruption behaves differently.

What an attacker gains

MITRE lists quality degradation, varying by context. There is no direct exploit. But an attacker who can trigger the slow path repeatedly can tie up request threads, since the work meant to run in the background now holds them. That turns a quality bug into a denial of service risk.

How to find it

MITRE says automated static analysis can find some instances. Look for .run() calls on Thread objects, and review any test where a "background" task finishes suspiciously in order. Thread dumps that show your worker code on a request thread are a clear sign.

How to fix it

MITRE's mitigation: use the start() method instead of the run() method.

// Fixed
Thread thr = new Thread(() -> doWork());
thr.start();

For anything beyond a one off, an ExecutorService gives you pooling, limits and clean shutdown, and avoids creating raw threads.

  1. Replace the call with start(), or submit the task to an executor.
  2. Confirm that the shared state touched by the task is safe to use across threads.
  3. Add a test that checks the work ran on a different thread.

The free in-browser scan at gold.safeguard.sh/scan lists the dependencies in your manifest. No login is needed, the file stays on your machine, and it handles up to 100 dependencies.

Quick check

What does calling run() directly do?

It runs the method in the current thread like any normal method call. No new thread is created.

What is the fix?

Call start(), or submit the task to an executor.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.