Figma — Server-side sandboxing — An introduction¶
Summary¶
Part 1 of Figma's security-engineering 3-part series on server-side sandboxing (a.k.a. workload isolation) — the umbrella intro that frames why you'd sandbox server-side code in the first place, what the three canonical primitives are (VMs, containers, seccomp), and what questionnaire Figma uses to pick among them. The motivating example is ImageTragick (2016): a critical RCE in the ImageMagick library that allowed remote code execution in any service running it on user-provided images server-side. Image processing, parsing, compression, and thumbnailing libraries are typically written in memory-unsafe languages like C++, seldom designed to handle hostile input, and the premise behind sandboxing is simple: "Buggy software is a fact of life, security threats are inevitable, and it's nearly impossible to prevent all vulnerabilities." Accept that vulnerabilities will exist, and bound the blast radius of exploitation instead. Part 2 (VMs) deep-dives the hypervisor-isolation row; Part 3 (containers + seccomp) covers the kernel-isolation rows and Figma's RenderServer production exemplar.
Key takeaways¶
-
Sandboxing is defence-in-depth, not a replacement for secure code. The security model Figma articulates: "It's expensive and unrealistic to rely entirely on preventing security vulnerabilities. Instead, we also use sandboxing to mitigate the impact of those bugs when they do come up." The sandbox exists because the inner code is assumed to be exploitable — third-party image libraries, document converters, browser engines, anything fetching over a URL. (Source: this article)
-
The risk class is memory-unsafe code processing hostile input. Figma's framing: "the libraries that perform these operations are written in memory-unsafe languages like C++. Many popular libraries have a history of memory corruption vulnerabilities." ImageMagick is the named canonical instance; the pattern generalises to parsers, decompressors, thumbnailers, any C/C++ code fed user bytes. See concepts/memory-safety for the language-level root cause and concepts/internally-generated-untrusted-input for the "hostile-input-on-the-inside" framing.
-
Rewriting in memory-safe languages is a valid but insufficient alternative. Figma considers it and rejects it as a primary strategy: "One solution would be to rewrite all of our unsafe code in a memory-safe language and leverage program analysis techniques to prove its correctness and security properties. But as with many other complex real-world systems, this would require pulling resources away from other critical security projects and in turn present a number of other trade-offs. (Even then, there's still a risk that we might inadvertently introduce a security bug anyway, because no methods are foolproof. We're all human.)" Sandboxing is additive, not exclusive.
-
Three canonical primitives, in decreasing strength/cost. Figma's mental model for practical options:
| Primitive | Boundary | Figma usage |
|---|---|---|
| Virtual machines / micro-VMs | Hypervisor (hardware virt) | Firecracker via AWS Lambda for link-metadata + canvas image fetchers |
| Containers | Kernel namespaces + cgroups | nsjail wrapping RenderServer's GPU path |
| seccomp (secure computing mode) | Kernel syscall allowlist | Post-refactor seccomp-only for RenderServer's non-GPU path, via libseccomp |
"There are several approaches to building a security sandbox: virtual machines (VMs), containers, and secure computing mode (seccomp)." Parts 2 + 3 deep-dive rows 1 and 2+3 respectively.
-
Client-side sandboxing is a separate problem with its own techniques. Figma names WebAssembly as its client-side sandboxing primitive (the canvas is C++-to-WASM, sandboxed inside the browser). Server-side sandboxing is about protecting Figma's infrastructure from user-provided graphical data; the two are orthogonal.
-
Sandboxing's whole point is minimising what a compromise can reach. Figma's articulation: "At Figma, we don't want to run jobs on potentially malicious input directly inside our infrastructure. If we did, one serious bug could allow that job to access user data from other jobs, make requests to other production services, or move laterally and compromise additional components of production." Sandboxing "minimize[s] and better manage[s] the external interfaces and resources that a compromised workload can access, effectively containing an attack to the affected system." Canonical wiki instance of concepts/defense-in-depth applied at the workload-isolation layer.
-
seccomp's dev-cost-vs-security trade-off is explicitly named. Figma frames the three primitives along a cost gradient: "while a seccomp-driven approach offers generally strong security properties and minimal runtime overhead, it may involve substantial initial development cost. Meanwhile, a container-driven approach has more potential security pitfalls and often reduced runtime performance, but is likely far easier to ship." No linear winner; pick the lightest that gives you the boundary you actually need.
-
A 12-question evaluation questionnaire (condensed in four families). Figma's decision framework for picking a primitive, quoted from the post and grouped:
-
Environment — Does your workload need a specific OS / specialized environment?
- Security + performance — How strong a sandbox? How much attack surface is acceptable? Per-job / per-user / per-project isolation? Latency tolerance? Compute budget?
- Development cost + friction — Tailor-made or drop-in? Development complexity budget? Debugging-access needs?
- Maintenance + operational overhead — Code under active development? Willing to run your own service? Who owns it long-term?
These four axes show up again on concepts/server-side-sandboxing and are the structure Part 2 and Part 3 are organised around.
Systems / concepts / patterns extracted¶
Systems:
- systems/figma-renderserver — C++ headless Figma editor for thumbnailing + SVG export; named as a Figma-authored memory-unsafe server-side component that itself needs sandboxing. Deep-dived in Part 3.
- systems/firecracker — AWS's micro-VM hypervisor, named as Figma's VM-primitive-of-choice via Lambda. Deep-dived in Part 2.
- systems/aws-lambda — the managed-Firecracker wrapper Figma uses for link-metadata + canvas image fetchers. Deep-dived in Part 2.
- systems/nsjail — Google's cmdline tool stacking namespaces + capabilities + filesystem restrictions + cgroups + resource limits
- seccomp. Figma's container-primitive-of-choice for RenderServer. Deep-dived in Part 3.
- systems/docker — named as the usual container baseline against which nsjail is the drop-in alternative.
Concepts:
- concepts/server-side-sandboxing — the umbrella concept; three-primitive table + two-question frame + four-axis trade-off grid.
- concepts/memory-safety — why C/C++ libraries keep shipping memory-corruption CVEs; the root cause sandboxing mitigates (rather than fixes).
- concepts/defense-in-depth — the architectural tenet that sandboxing realises at the workload layer.
- concepts/threat-modeling — what you do before picking a primitive; the questionnaire is a threat-modeling artifact.
- concepts/vm-escape / concepts/container-escape — the two escape modes Parts 2 and 3 deep-dive.
- concepts/seccomp / concepts/syscall-allowlist / concepts/linux-namespaces — kernel primitives reviewed in Part 3.
- concepts/internally-generated-untrusted-input — user-supplied images / documents / SVGs arriving inside the service's trust boundary; the reason sandboxing exists.
Patterns:
- patterns/minimize-vm-permissions — deep-dived in Part 2; named here as the "contain the attack to the affected system" mechanism.
- patterns/refactor-for-seccomp-filter — deep-dived in Part 3.
- patterns/seccomp-bpf-container-composition — deep-dived in Part 3.
Operational numbers disclosed¶
- None. This is Part 1 (the intro); quantitative disclosures (cold- start latency, rlimit defaults, allowlist surface) live in Parts 2 and 3. The only concrete reference is to ImageTragick (2016) as the historical motivating CVE.
Caveats¶
- Introduction piece, not a deep-dive. The three-primitive comparison is intentionally high-level; architectural substance is in the linked Parts 2 + 3 which are both already ingested on this wiki.
- The post does not disclose Figma's internal sandboxing decision process beyond the questionnaire — no concrete example of a workload-to-primitive mapping beyond the named production systems (AWS Lambda for link fetching, nsjail / seccomp-only for RenderServer, which are Part 2 + Part 3 content).
- Embedded external links — the post references Fly.io's own workload isolation post
- WebAssembly security docs as sibling framings; not ingested here.
- Frames sandboxing as additive to memory-safe-language rewrites, not a substitute — honest but means the post cannot be read as an argument against rewriting RenderServer in Rust; Figma has already done so for the Multiplayer server and still uses sandboxing on top.
- No production incident retrospective. ImageTragick is cited historically (2016); no Figma-specific near-miss or actual exploitation is disclosed.
- Questionnaire is qualitative. No weights, no tie-breakers, no worked decision example mapping a specific workload to a primitive through the 12 questions.
Source¶
- Original: https://www.figma.com/blog/server-side-sandboxing-an-introduction/
- Raw markdown:
raw/figma/2026-04-21-server-side-sandboxing-an-introduction-3b3864dc.md
Related¶
- sources/2026-04-21-figma-server-side-sandboxing-virtual-machines — Part 2 of the series (VMs row of the primitive table; Firecracker
- AWS Lambda production instance).
- sources/2026-04-21-figma-server-side-sandboxing-containers-and-seccomp — Part 3 of the series (containers + seccomp rows; nsjail + seccomp-only-after-refactor on RenderServer).
- concepts/server-side-sandboxing — umbrella concept; three- primitive table + two-question frame + four-axis trade-off grid.
- concepts/memory-safety — why the inner code keeps needing a sandbox.
- concepts/defense-in-depth — architectural tenet realised here.
- companies/figma — operator.
- Sibling Figma 2026-04-21 security-engineering posts: sources/2026-04-21-figma-visibility-at-scale-sensitive-data-exposure, sources/2026-04-21-figma-how-we-built-a-custom-permissions-dsl, sources/2026-04-21-figma-rolling-out-santa-without-freezing-productivity, sources/2026-04-21-figma-enforcing-device-trust-on-code-changes.