alyssaxuu/screenity · critical · Error
Untrusted TUS location host: ${parsed.host}
Error message
Untrusted TUS location host: ${parsed.host} What it means
Defense-in-depth check: after resolving the TUS Location header, the uploader refuses any session URL whose host is not video.bunnycdn.com. A malicious or misbehaving redirect could otherwise send recording chunks plus the AuthorizationSignature header to an attacker-controlled host.
Source
Thrown at src/pages/CloudRecorder/bunnyTusUploader.js:1225
VideoId: this.videoId,
"Upload-Metadata": `filetype ${btoa(this.container || "video/webm")},title ${btoa(
this.metadata.title,
)}`,
},
});
if (!res.ok) throw new Error("Failed to start TUS upload session");
const location = res.headers.get("location");
const resolved = location.startsWith("/")
? `https://video.bunnycdn.com${location}`
: location;
// Defense-in-depth: TUS Location header must stay on Bunny's host. Without
// this, a redirect to attacker.com would receive subsequent PATCHes
// carrying recording chunks plus the AuthorizationSignature header.
try {
const parsed = new URL(resolved);
if (parsed.host !== "video.bunnycdn.com") {
throw new Error(`Untrusted TUS location host: ${parsed.host}`);
}
} catch (err) {
throw new Error(`Invalid TUS location: ${err?.message || err}`);
}
this.uploadUrl = resolved;
// Persist BEFORE save-upload-meta: the local journal is the only recovery
// path if the extension crashes before the backend records the URL.
await this.persistUploadJournal({ force: true });
if (this.userToken) {
fetch(`${API_BASE}/bunny/videos/save-upload-meta`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.userToken}`,
},
body: JSON.stringify({View on GitHub (pinned to 512606387b)
Solutions
- Check for proxies, VPNs, or corporate MITM tools rewriting response headers
- Log the raw Location header to confirm what Bunny actually returned
- If Bunny changes its upload hostname, update the allowlist constant deliberately after verifying the new host
- Report unexpected hosts to Bunny support; treat the recording/signature as compromised
Example fix
// before
if (parsed.host !== "video.bunnycdn.com") {
throw new Error(`Untrusted TUS location host: ${parsed.host}`);
}
// after
const ALLOWED_HOSTS = new Set(["video.bunnycdn.com"]);
if (!ALLOWED_HOSTS.has(parsed.host) || parsed.protocol !== "https:") {
throw new Error(`Untrusted TUS location host: ${parsed.host}`);
} Defensive patterns
Strategy: validation
Validate before calling
const host = new URL(location, "https://video.bunnycdn.com").host;
if (host !== "video.bunnycdn.com") {
alertHostMismatch(host); // investigate proxy/MITM before retrying
} Type guard
function isTrustedTusLocation(loc) {
try { return new URL(loc).host === "video.bunnycdn.com"; }
catch { return false; }
} Try / catch
try {
await uploader.init();
} catch (e) {
if (String(e.message).startsWith("Untrusted TUS location host")) {
reportSecurityIncident(e.message); // do NOT auto-retry
}
} Prevention
- Never disable the host allowlist check
- Investigate proxies/VPNs if this fires; the signature must be considered leaked
- Keep the allowlist constant centralized and reviewed
- Alert on this error in telemetry — it may indicate MITM
When it happens
Trigger: Bunny (or an intercepting proxy/CDN) returns a Location header pointing at a different host, or the resolved location string is malformed such that new URL() parses a non-Bunny host.
Common situations: Corporate proxy rewriting Location headers; a man-in-the-middle or compromised endpoint returning attacker.com; Bunny changing/aliasing its upload hostname after a config update.
Related errors
- Uploader has already been initialized
- resume-offset-unverified
- Failed to start TUS upload session
- Invalid TUS location: ${err?.message || err}
- write-after-finalize
AI-assisted analysis of alyssaxuu/screenity@512606387b (2026-09-02).
Data as JSON: /api/errors/2963c919da3fdb1a.
Report an issue: GitHub.