C.W.K.
Stream
Lesson 06 of 06 · published

Tool 보안: permissions · sandbox · side effects

~14 min · security, permissions, side-effects

Level 0Observer
0 XP0/64 lessons0/13 achievements
0/150 XP to next level150 XP to go0% complete

Tool description은 public

도구 description에 쓰는 건 도구 언급되는 매 호출에 Anthropic으로 감. 호스트네임, 내부 경로, 테이블 이름, 시크릿 힌트 포함. 배포 전 시크릿 strip — description은 private 노트 필드 X.

Side effect는 명시적 권한 필요

Read 도구(search, lookup, get)는 보통 unattended 실행 OK. Write 도구(create, modify, delete)는 human-in-the-loop 체크 받을 가치. Agent SDK가 permission 프롬프트로 네이티브 지원; Client SDK에선 너가 빌드. 어느 쪽이든 모델이 acknowledgment 없이 destructive side effect trigger 절대 X.

위험한 거 sandbox

Tool이 셸 명령 실행, 코드 실행, 파일시스템 hit하면 샌드박스에 살아 — 제한된 env vars, 작업 디렉토리 화이트리스트, 시간 예산, 출력 크기 cap. Anthropic의 code_execution이 샌드박스에서 도는 거; 너 커스텀 도구도 매치해야.

원칙: Tool엔 권한 있어. Untrusted user한테 노출된 새 API 엔드포인트 audit하듯 매 도구 audit.

Code

Write tool 주변 permission gate·python
import os, json

DESTRUCTIVE = {"delete_file", "drop_table", "send_email"}

async def gated_invoke(block, ask_user):
    args_str = json.dumps(block.input, indent=2)
    if block.name in DESTRUCTIVE:
        approved = await ask_user(f"Allow {block.name} with args:\n{args_str}")
        if not approved:
            return {"type": "tool_result", "tool_use_id": block.id,
                    "is_error": True, "content": "user denied permission"}
    handler = HANDLERS[block.name]
    out = await handler(**block.input)
    return {"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(out)}
시간 예산 가진 sandbox 셸 도구·python
import asyncio, shlex

ALLOWED = {"ls", "cat", "grep", "head", "tail"}

async def safe_shell(command: str, timeout: float = 5.0):
    parts = shlex.split(command)
    if not parts or parts[0] not in ALLOWED:
        raise PermissionError(f"command not in allowlist: {parts[0] if parts else ''}")
    proc = await asyncio.create_subprocess_exec(
        *parts,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
        cwd="/sandbox",  # 화이트리스트 작업 디렉토리
        env={"PATH": "/usr/bin:/bin"},  # minimal env
    )
    try:
        out, err = await asyncio.wait_for(proc.communicate(), timeout=timeout)
    except asyncio.TimeoutError:
        proc.kill()
        raise TimeoutError("command exceeded time budget")
    return {"stdout": out.decode()[:8192], "stderr": err.decode()[:2048], "returncode": proc.returncode}

External links

Exercise

Side effect 가진 프로젝트 도구 하나 audit. Permission gate, sandbox 경계, audit 로그 entry 추가. 도구가 permission 없이 거부 증명하는 테스트로 각각 검증.
Hint
Tool이 confirmation 없이 DB 테이블 drop 가능하면 prod 사고 기다리는 중.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.