Garden의 핵심 기능인 샌드박싱을 통해 신뢰할 수 없는 코드를 안전하게 실행하고, 인터랙티브 문서, 즉시 평가, 라이브러리 추측 로딩, 프로그램 합성, AI 도구 등 다양한 워크플로를 가능하게 하는 방법을 살펴본다.
URL: https://www.garden-lang.org/blog/sandbox.html
Title: 개발 일지 2: 샌드박싱의 중요성
2026-01-06
Garden의 핵심 기능은 신뢰할 수 없는 코드를 샌드박스에서 실행할 수 있다는 점입니다. 신뢰할 수 없는 평가(untrusted evaluation)는 기존 언어에 추가하기가 극도로 어렵지만, Garden은 완전히 새로 만들어진 언어입니다. 샌드박싱은 정말 흥미로운 워크플로들을 가능하게 합니다.
이 웹사이트의 모든 코드 스니펫에는 Run(실행)과 Edit(편집) 버튼이 있습니다. 어떤 기능을 제대로 이해했는지 확인하고 싶다면 직접 실험해볼 수 있습니다.
아주 간단한 예시는 다음과 같습니다.
임의의 코드를 허용하는 만큼, 사용자가 (실수로든 의도적으로든) 더 문제될 만한 코드를 작성할 수도 있습니다. 샌드박스는 이를 안전하게 실행할 수 있도록 보장합니다.
Path{ p: "/etc/passwd" }.read()
일부 프로그래밍 언어는 인터프리터를 wasm으로 컴파일하는 방식을 택해 실행이 브라우저에서 이뤄지도록 합니다. 이는 안전합니다 — 모든 일이 독자의 머신에서 일어나니까요 — 하지만 모바일에서는 느립니다. 또한 wasm 빌드는 인터프리터에 추가적인 제약을 부과하기도 합니다.
이 웹사이트의 스니펫들은 제 서버에서 실행되며, 인터프리터의 샌드박스 기능을 사용합니다. 이를 배포하는 것은 무섭기도 했습니다(서비스로서의 원격 코드 실행이라니!) 하지만 그만한 경험적 가치가 있다고 생각합니다. 전용 월 $1짜리 서버에서 Docker 컨테이너로 실행 과정을 철저히 잠가 두었습니다.
만약 보안 버그를 발견하신다면, 버그 트래커에 이슈를 열어 주시거나 이메일로 연락해 주세요.
JavaScript는 성숙한 샌드박스를 갖춘 몇 안 되는 언어 중 하나이며, 현대 웹의 핵심 요소입니다. JavaScript는 또한 콘솔에서 스니펫을 안전하게 즉시(eagerly) 실행하는 기능을 갖고 있습니다.
제가 엔터를 누르기 전인데도 인터프리터가 "FOO"를 보여주는 것을 확인할 수 있습니다. 이건 작은 기능이지만, 한번 익숙해지고 나면 다른 언어에서 그 기능이 없을 때 아쉬움을 느끼게 됩니다. 키 입력을 줄여주고 더 빠르게 피드백을 받을 수 있게 해주기 때문입니다.
Garden은 아직 REPL에서 즉시 평가를 지원하진 않지만, 샌드박스에서 테스트를 즉시 평가할 수는 있습니다. 즉시 테스트는 하드웨어도 더 잘 활용합니다. 저는 코드를 작성하는 동안 제 머신이 대체로 한가한 경우가 많지만, 사실 그 시간에 도움을 줄 수도 있죠!
이 비디오에서 코드를 편집할 때 실패하는 assertion이 즉시 바뀌는 점에 주목해 주세요.
샌드박스 테스트는 안전한 변이 테스트(mutation testing)도 가능하게 합니다. 놀라울 정도로 많은 변이 테스트 프레임워크가, 테스트 스위트에 대한 작은 변경은 검토 없이도 안전하게 실행할 수 있다고 그냥 가정해 버립니다.
이상적인 세계라면, JavaScript에서 require("lodash")를 작성하는 것만으로 충분해야 합니다. IDE가 라이브러리를 설치해 주고, 추가 키 입력은 필요 없어야 하죠.
이를 실제로 구현한 프로젝트도 있습니다(예: auto-install for JS). 하지만 샌드박스 없이는 안전하지 않습니다. 허용 목록(allowlist)으로 허용된 패키지만 설치하게 하거나, post-install 스크립트를 금지하는 식으로 위험을 줄일 수는 있지만, 어딘가 어설프고 투박한(janky) 방식입니다.
샌드박스가 있다면 이런 워크플로를 제대로 지원할 수 있습니다.
저는 종종, 프로그램의 나머지 부분이 뻔히 보이는 프로그램을 작성하곤 합니다.
이는 ‘프로그램 합성(program synthesis)’ 문제로, 예시를 바탕으로 컴퓨터가 코드를 작성하게 하는 것입니다. 단순한 브루트포스 해법(‘열거 기반 합성’, enumerative synthesis)을 적용할 수도 있고, 더 똑똑한 타입 기반 탐색을 할 수도 있으며, 또는 LLM에 그냥 맡길 수도 있습니다.
샌드박스가 있다면, 명백한 모든 가능성을 평가해 보고 — 테스트를 통과한다면 — 사용자에게 제안할 수 있습니다.
LLM은 코드를 반복 개선하는 데 꽤 능숙합니다. 에이전트형 도구(agentic tools)는 출력(정적 오류, 런타임 오류, 테스트 실패 등)을 처리하는 LLM 루프에 의존합니다. 이는 종종 LLM이 동작하는 구현을 작성하도록 유도하는 데 충분합니다.
이 사용 사례는 너무 매력적이라서, 일부 사용자는 자신의 머신에서 직접 --dangerously-skip-permissions를 실행하기도 합니다. Claude는 Docker 컨테이너에서 실행하는 방법을 안내하고 있으며, claude.ai/code는 이 워크플로를 안전하게 허용하기 위해 격리된 VM도 제공합니다.
이런 워크플로는 AI가 예를 들어 파일을 전부 삭제하는 일을 막아주지만, 원하는 해법으로 AI를 상호작용적으로(interactively) 유도하기는 더 어려워집니다. 샌드박스는 LLM과 인터프리터를 일반 프로그램처럼 실행할 수 있게 해주어, 두 세계의 장점을 모두 취할 수 있게 합니다.
임의의 코드 실행을 안전하게 지원하는 것은, 제가 지금까지 작성한 코드 중 가장 무섭고 보안에 민감한 작업입니다. 제 보안 태세를 정리하기 위해 꽤 오랜 시간을 들였습니다.
Garden 인터프리터 샌드박스는 I/O(디스크, 네트워크)를 막고 리소스 제한도 강제합니다. 현재 구현은 메모리 제한에 대해 약간 느슨한 편이라, 충분히 문제 있는 프로그램이라면 여전히 인터프리터를 OOM(메모리 부족)으로 만들 수 있습니다.
샌드박스는 rowhammer나 spectre 같은 사이드 채널 공격에 대한 보호를 제공하지 않습니다.
웹사이트에서 라이브 평가가 가능하다는 점이 정말 기쁘지만, 이 샌드박스 위에 구축할 수 있는 기능은 아직도 엄청나게 많습니다.
Garden은 아직 알파 단계 소프트웨어이지만, 직접 써보고 싶다면 GitHub에 모두 공개되어 있습니다.