Repository navigation
Description
Describe the bug
Security Advisory: Unsandboxed Headless Chromium Execution & Disabled Site Isolation in Cloud Rendering Workers
Target Package: @hyperframes/engine / @hyperframes/producer
Also Affects: @hyperframes/aws-lambda, @hyperframes/gcp-cloud-run
Severity: High (CVSS 8.2 — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N)
CWE Classification:
CWE-693: Protection Mechanism Failure
CWE-250: Execution with Unnecessary Privileges
CWE-265: Privilege / Sandbox Issues
Executive Summary
In HyperFrames, headless Chromium is launched with flags that completely strip the operating system kernel security sandbox (--no-sandbox, --disable-setuid-sandbox) and disable Chromium's process-level site isolation features (IsolateOrigins, site-per-process).
While this configuration is commonly used as a convenience flag to bypass Linux user namespace restrictions during local container development, HyperFrames uses these identical engine primitives across its production cloud rendering packages (@hyperframes/aws-lambda and @hyperframes/gcp-cloud-run).
Because HyperFrames inherently executes untrusted, user-authored HTML, CSS, JavaScript, WebGL shaders, and WebGPU workloads to render video frames, disabling the Chromium sandbox eliminates the primary line of defense. An attacker who supplies a malicious video composition exploiting a Chromium V8, Blink, Dawn (WebGPU), or SwiftShader memory corruption vulnerability achieves instant, unsandboxed container execution in the host environment, compromising cloud IAM temporary credentials, adjacent storage buckets, and host resources.
Affected Source Coordinates
File: packages/engine/src/services/browserManager.ts
Coordinate: Lines 1145–1151 and Line 1184
typescript
// packages/engine/src/services/browserManager.ts
const chromeArgs = [
"--no-sandbox", // <--- Disables Linux user/pid namespaces & chroot sandbox
"--disable-setuid-sandbox", // <--- Disables SUID sandbox fallback
"--disable-dev-shm-usage",
softwareWebGpu
? ${CANVAS_DRAW_ELEMENT_FEATURE_FLAG},Vulkan
: CANVAS_DRAW_ELEMENT_FEATURE_FLAG,
"--enable-webgl",
"--ignore-gpu-blocklist",
...getBrowserGpuArgs(browserGpuMode, platform),
// ...
// Line 1184: Explicitly strips site isolation and origin boundaries
"--disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,IntensiveWakeUpThrottling",
"--autoplay-policy=no-user-gesture-required",
];
Technical Root Cause
Unconditional Sandbox Suppression: The buildChromeArgs() helper in browserManager.ts does not differentiate between a single-tenant local CLI execution on a trusted machine and a multi-tenant cloud worker rendering untrusted assets.
Disabled Site Isolation: Passing --disable-features=IsolateOrigins,site-per-process instructs Chromium to run cross-origin iframes and scripts within the same renderer process, collapsing origin boundary protections.
Execution Model Disconnect: Unlike document generators that render static text, HyperFrames deliberately evaluates arbitrary JavaScript in the page (to drive GSAP timelines, physics simulations, WebGL shaders, and canvas mutations). Executing arbitrary client code inside an unconfined browser process removes all layers of defense-in-depth.
Threat Model & Attack Scenario
Attacker Submits Video Composition (HTML/JS/WebGL)
│
▼
Cloud Worker (AWS Lambda / GCP Cloud Run)
│
▼
Puppeteer launches Chromium with [--no-sandbox, --disable-setuid-sandbox]
│
▼
Chromium executes untrusted page JS / WebGL shader
│
▼
Exploitation of V8 / Blink / WebGPU vulnerability (e.g. type confusion or buffer overflow)
│
▼ (NO OS SANDBOX / NO USER NAMESPACE BARRIER)
Direct Code Execution as Container Process UID
│
▼
Container & Cloud Compromise:
- Reads AWS / GCP metadata and temporary IAM execution role credentials
- Accesses S3 / GCS buckets containing other tenants' renders
- Exfiltrates environment variables and configuration secrets
Vector: A user or malicious third-party submits an HTML composition, template, or sub-composition to a hosted HyperFrames rendering service (e.g., via AWS Lambda Step Functions or Cloud Run API).
Trigger: The headless browser loads index.html to begin frame extraction.
Exploit: The composition runs JavaScript triggering a memory corruption flaw in V8 or a WebGL/WebGPU shader parsing flaw.
Impact: Because --no-sandbox is set, the payload does not get trapped in an unprivileged broker/renderer jail. It inherits the exact permissions, capabilities, and filesystem access of the parent Node.js container process.
Remediation & Actionable Patch
- Conditional Sandbox Flag in Browser Manager
Do not apply --no-sandbox by default. Require an explicit environment override when running in restricted test runners:
diff
--- a/packages/engine/src/services/browserManager.ts
+++ b/packages/engine/src/services/browserManager.ts
@@ -1142,9 +1142,12 @@ export function buildChromeArgs(options: BuildChromeArgsOptions, config?: GpuCon
// fairly standard "headless-for-capture" configuration — similar profiles
// appear in Puppeteer's defaults, Playwright, Remotion, and Chrome's own
// headless-shell guidance.
- const allowNoSandbox = process.env.HYPERFRAMES_ALLOW_NO_SANDBOX === "1";
- const chromeArgs = [
- "--no-sandbox",
- "--disable-setuid-sandbox",
- ...(allowNoSandbox ? ["--no-sandbox", "--disable-setuid-sandbox"] : []),
"--disable-dev-shm-usage",
softwareWebGpu
?${CANVAS_DRAW_ELEMENT_FEATURE_FLAG},Vulkan
@@ -1181,7 +1184,8 @@ export function buildChromeArgs(options: BuildChromeArgsOptions, config?: GpuCon
"--disk-cache-size=268435456",
...getLowMemoryFlags(),
// Disable features that add overhead
- "--disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,IntensiveWakeUpThrottling",
- // Retain site-per-process and IsolateOrigins for origin isolation
- "--disable-features=AudioServiceOutOfProcess,Translate,BackForwardCache,IntensiveWakeUpThrottling",
// Allow AudioContext to start without a user gesture in headless Chrome.
"--autoplay-policy=no-user-gesture-required",
];
- Architecture Boundary (For Cloud Deployments)
For cloud rendering infrastructure handling multi-tenant or untrusted workloads:
MicroVM Isolation: Wrap each distributed render chunk in a hardware-isolated microVM (such as AWS Firecracker or gVisor runtime) rather than executing inside a long-lived or shared container with IAM role permissions.
Dedicated Rendering IAM Roles: Strip the Lambda / Cloud Run execution role of any privileges beyond reading the specific input task and writing to the designated tenant prefix in S3/GCS (arn:aws:s3:::bucket/renders/${tenant_id}/*).
Discovery Provenance
Discovered by: Black Datum Security Audit Engine
Verification Gate: Confirmed via Static AST Analysis and Engine Launch Trace
Validation Status: Formally registered in findings.json as hyperframes-chromeargs-nosandbox
Minimal reproduction
Reproduction Fixture: Headless Chromium Sandbox Verification
This reproduction demonstrates the issue in two ways:
Direct Flag Inspection (Programmatic/Unit): Evaluates the exact argument array assembled by @hyperframes/engine without requiring external network access.
End-to-End Process Audit (Runtime): Runs a render of a minimal synthetic project and inspects the live command line of the spawned Chromium process.
- Setup the Minimal Synthetic Composition
Create an empty directory containing a valid, minimal HyperFrames composition index.html:
bash
mkdir hyperframes-sandbox-repro
cd hyperframes-sandbox-repro
Create index.html:
html
<title>Synthetic Reproduction Project</title> <style> body { margin: 0; background: #000; color: #fff; display: flex; align-items: center; justify-content: center; height: 100vh; font-family: sans-serif; } </style>Sandbox Flag Audit Test
Inside the repository or project directory, execute this Node.js script to inspect the argument vector assembled by the engine:
javascript
// test-sandbox-flags.mjs
import { buildChromeArgs } from "@hyperframes/engine";
// Assemble default launch options for a standard 1920x1080 capture
const options = { width: 1920, height: 1080 };
const args = buildChromeArgs(options);
console.log("=== HyperFrames Assembled Chromium Flags ===");
const flagsToCheck = [
"--no-sandbox",
"--disable-setuid-sandbox",
"IsolateOrigins",
"site-per-process"
];
for (const flag of flagsToCheck) {
const matched = args.find(a => a.includes(flag));
if (matched) {
console.log([!] CRITICAL FLAG FOUND: ${matched});
} else {
console.log([OK] Flag not present: ${flag});
}
}
Run the script:
bash
node test-sandbox-flags.mjs
Observed Output:
text
=== HyperFrames Assembled Chromium Flags ===
[!] CRITICAL FLAG FOUND: --no-sandbox
[!] CRITICAL FLAG FOUND: --disable-setuid-sandbox
[!] CRITICAL FLAG FOUND: --disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,IntensiveWakeUpThrottling
[!] CRITICAL FLAG FOUND: --disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,IntensiveWakeUpThrottling
3. Runtime Process Audit (Live Execution)
To observe the actual running Chromium process arguments during an active render:
On Linux / macOS:
Start the render in the background:
bash
npx hyperframes render index.html --format=mp4 &
Immediately inspect the live Chromium process arguments:
bash
ps aux | grep -E "(chrome|chromium)" | grep "no-sandbox"
On Windows (PowerShell):
Start the render:
powershell
npx hyperframes render index.html --format=mp4
In a parallel PowerShell terminal, query the process command line:
powershell
Get-CimInstance Win32_Process -Filter "Name LIKE '%chrome%'" | Select-Object -ExpandProperty CommandLine
4. Expected Diagnostic Evidence
The spawned process string confirms:
Chromium is running with --no-sandbox (bypassing Linux user namespaces, PID namespaces, and seccomp BPF filters).
Chromium is running with --disable-setuid-sandbox.
--disable-features=...,IsolateOrigins,site-per-process is active on the command line.
This confirms that in any containerized or cloud worker environment (such as the default AWS Lambda andThis request was blocked by Gemini's filters. They can occasionally trigger by mistake on safe coding, security, or biology-related queries. Please try rephrasing your prompt. You can send feedback
or read more about our policies here
.
Steps to reproduce
Step-by-Step Verification Instructions
Method 1: Direct Repository Unit Check (Fastest)
Open a terminal in the root of the cloned hyperframes repository:
bash
cd hyperframes
Create a test verification script verify-flags.mjs:
javascript
import { buildChromeArgs } from "./packages/engine/src/services/browserManager.ts";
const args = buildChromeArgs({ width: 1920, height: 1080 });
console.log("Assembled Chromium Arguments:\n");
const targetFlags = ["--no-sandbox", "--disable-setuid-sandbox", "IsolateOrigins", "site-per-process"];
for (const flag of targetFlags) {
const match = args.find(a => a.includes(flag));
if (match) {
console.log([FLAG CONFIRMED] ${match});
} else {
console.log([ABSENT] ${flag});
}
}
Execute the script using Node or tsx:
bash
npx tsx verify-flags.mjs
Expected Output:
text
Assembled Chromium Arguments:
[FLAG CONFIRMED] --no-sandbox
[FLAG CONFIRMED] --disable-setuid-sandbox
[FLAG CONFIRMED] --disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,IntensiveWakeUpThrottling
[FLAG CONFIRMED] --disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,IntensiveWakeUpThrottling
Method 2: Live Render Process Inspection
Create a minimal test composition index.html:
html
Test
Start a test render:
bash
npx hyperframes render index.html --format=mp4
While the render is active, inspect the running Chromium command line in a separate terminal:
Linux / macOS:
bash
pgrep -a -f "(chrome|chromium)" | grep "no-sandbox"
Windows (PowerShell):
powershell
Get-CimInstance Win32_Process -Filter "Name LIKE '%chrome%'" | Select-Object -ExpandProperty CommandLine
Result: The output shows the active Chromium process running with --no-sandbox and --disable-setuid-sandbox.
Expected behavior
Expected Behavior and Real-World Impact
- With Standard JavaScript Payloads
Expected Result: No compromise.
Explanation: The --no-sandbox flag disables OS kernel boundaries, but Chromium's standard web security model remains active in the DOM. Standard browser APIs cannot read arbitrary local filesystem files or spawn host shell commands. - When Chained with a Browser Engine Defect
Expected Result: Immediate container or host compromise.
Explanation: In a standard browser, an exploit targeting a memory corruption defect in the renderer (V8 or WebGPU) is trapped inside an unprivileged sandbox jail. Because HyperFrames disables the sandbox, the requirement for a separate sandbox escape exploit is eliminated. The payload executes directly with the privileges of the parent process. - In Cloud Environments (AWS Lambda / GCP Cloud Run)
Expected Result: Exposure of cloud execution roles and environment secrets.
Explanation: When processing untrusted user compositions on cloud workers, any successful renderer exploit gains immediate access to:
Ephemeral cloud provider credentials (AWS_ACCESS_KEY_ID, AWS_SESSION_TOKEN, or GCP service account tokens via local metadata endpoints).
Environment variables and adjacent files mounted in /tmp.
External resources permitted by the container's execution role.
Actual behavior
i did not use any red hat methods to breach.
Environment
hyperframes doctor
✓ Version 0.9.39 (up to date)
✓ CLI binary npx / bunx · C:\Users\Mrdin\AppData\Local\npm-cache\_npx\hyperframes\bin\hyperframes.mjs
✓ Node.js v26.13.0 (win32 x64)
✓ CPU 16 cores · AMD Ryzen 7 3700X 8-Core Processor @ 4050MHz
✓ Memory 63.9 GB total · 49.8 GB available
✓ Disk 1820.9 GB free
✓ Frames cache C:\Users\Mrdin\AppData\Local\Temp\hyperframes-extract-cache-u · default
✓ Archive extractor Built into Windows
✓ Settings lock Not locked
✓ Environment OK
✓ whisper-cpp C:\ProgramData\chocolatey\bin\whisper-cli.exe (v1.7.1)
✓ TTS (Kokoro) Installed (kokoro-onnx 0.3.1)
✓ BGM (MusicGen) Installed (transformers + torch)
✓ onnxruntime-node Ready
✓ @google/genai Ready
✓ FFmpeg C:\ProgramData\chocolatey\bin\ffmpeg.exe (v7.1)
✓ FFprobe C:\ProgramData\chocolatey\bin\ffprobe.exe (v7.1)
✓ Chrome system: C:\Users\Mrdin\AppData\Local\Google\Chrome\Application\chrome.exe
✓ Docker Docker version 27.3.1
✓ Docker running Docker Desktop is running
✔ All checks passed — HyperFrames is fully operationalAdditional context
No response
Activity
fix(engine): launch Chrome with only the env it needs (heygen-com#7629)