6.0 KiB
Security and privacy
Trust boundary
Imported media, filenames, container metadata, tags, chapters, subtitles, attachments, codec logs, project JSON and Toolbox context are untrusted. FFmpeg parsing occurs in a worker but still consumes memory/CPU in the user's browser. The application cannot make a malicious codec safe; it limits exposure and keeps cleanup/recovery explicit.
The supported product has:
- no upload or processing backend;
- no telemetry, analytics or third-party runtime script;
- no remote-media protocol or automatic external fetch;
- no shell/native command execution;
- no arbitrary FFmpeg command input;
- no persistent source copy in the current application.
Browser extension, operating-system, reverse-proxy and compromised dependency behavior remain outside this boundary.
Paths and command construction
User names are display labels only. Virtual filesystem paths are generated from job ids plus sanitized, length-bounded basenames; separators, traversal, control characters, reserved names and collisions are handled centrally. Outputs must be declared in a typed plan before execution.
Commands are argument arrays assembled from discriminated operation/preset types. No shell parses them. Filters, metadata, concat lists, chapter metadata and subtitle values use syntax-specific escaping; one escaping routine is not reused across incompatible grammars. Capability requirements are checked before execution. Logs are line/byte bounded and local path-like names are redacted in exportable diagnostics.
Rendering and external URLs
Metadata is rendered as React text, never dangerouslySetInnerHTML. Subtitle
text is parsed and rendered or sent through a generated local file; it is not
inserted as HTML. Extracted URLs are inert text. The application does not open
links from media automatically. No remote font is fetched. Contact-sheet labels
mount only the same-origin, size/SHA-256-verified DejaVu asset and fail closed
without drawtext; ASS burn-in uses packaged/system-generic font configuration
only when the required local capability is available.
Preview/download URLs are blob: values made from local bytes. They are
revoked on replacement, project close and unmount. Browser support for a
container is not evidence that its contents are safe or fully decodable.
Resource controls
The administrator-adjustable defaults are product limits, not FFmpeg limits:
| Limit | Default |
|---|---|
| soft input warning | 256 MiB |
| hard single input | 1536 MiB |
| hard total input | 1536 MiB |
| soft output estimate | 512 MiB |
| hard output estimate | 1024 MiB |
| concurrent FFmpeg jobs | 1 |
| scheduled operations in memory | 8 |
| timeline clips | 100 |
| streams per input | 64 |
| image dimension / pixel count | 8192 / 67,108,864 |
| generated outputs / contact cells | 255 / 500 |
| job runtime | 4 hours |
Before allocation, the application estimates source/output bytes, duration, resolution, frame/pixel work, passes, retained results and output count. Estimates are labelled as estimates. Hard-limit violations do not start; soft violations explain resolution/duration/output-count alternatives. The 255-output limit keeps a whole managed batch saveable in the 256-entry ZIP limit with an optional report. Memory-constrained devices receive stronger warnings only when a reliable browser signal exists.
WASM itself has a documented 2 GiB input ceiling; practical browser limits can be much lower, especially when input and output coexist. Archive/export and cache operations also enforce entry, total-size and path limits.
Workers and cancellation
Wrapper, core, pthread and waveform workers are same-origin or short-lived
blob: workers created by trusted application code. OPFS caching currently
uses asynchronous browser file handles rather than a separate storage worker.
MT requires shared memory and cross-origin isolation. ST loads when isolation
is absent. Cancelling FFmpeg terminates and discards its worker/core; a new
instance is required before another job. Stale generations cannot commit a
result.
Content Security Policy
Tested deployment policy target:
default-src 'self';
script-src 'self' 'wasm-unsafe-eval';
worker-src 'self' blob:;
connect-src 'self';
img-src 'self' blob: data:;
media-src 'self' blob:;
font-src 'self';
style-src 'self';
object-src 'none';
frame-src 'none';
frame-ancestors 'none';
base-uri 'none';
form-action 'none';
Do not replace 'wasm-unsafe-eval' with broad 'unsafe-eval'. All core assets
are same-origin. media-src blob: is required for result/source previews.
The exact headers, immutable Portal reference gap and active-worktree local
patch are in docs/PORTAL_REQUIREMENTS.md.
Cross-origin isolation
MT needs secure HTTPS (localhost during development is acceptable),
SharedArrayBuffer, and:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
Isolation affects every resource in the page. Do not weaken COEP or allow cross-origin dependencies merely to make MT load. The safe fallback is ST.
Dependency and vulnerability response
Exact runtime versions and core digests are recorded in SOURCE.md. Run
npm audit, tests, real core smoke tests and legal review before an update.
Core upgrades change a large native attack surface and require new capability
snapshots, fixtures, checksums and browser tests.
Report vulnerabilities privately to the repository owner through the Gitea instance when possible. Do not attach sensitive media, credentials or an unredacted diagnostic log to a public issue. Include the app/core version, browser, mode, smallest synthetic reproduction, impact and cleanup result.