OpenClaw 자동화

AI가 내 컴퓨터에서 명령을 돌리기 전|OpenClaw exec 승인·허용 목록·상시 허가 읽는 법

깊음위에 2026. 9. 30. 08:26

AI 에이전트에게 일을 시키다가 이런 메시지를 받아 보신 분이 있을 거예요.

/approve 7f3a2b1c allow-once

에이전트가 내 컴퓨터에서 명령을 하나 돌리려는데 사람 허락을 기다리고 있다는 뜻입니다. 여기서 사람마다 반응이 갈립니다. 매번 물어보는 게 귀찮아서 다 열어 버리는 분도 있고, 무서워서 아예 막아 두는 분도 있어요. 둘 다 어디까지 열렸는지 모르는 상태가 된다는 점에서는 같습니다.

OpenClaw는 이 부분을 exec 승인(exec approvals)이라는 별도 층으로 다룹니다. 도구 정책이나 샌드박스와는 다른 층이고, 규칙이 생각보다 촘촘해요. 이 글은 OpenClaw 공식 문서 tools/exec-approvals.md와 tools/exec-approvals-advanced.md를 제가 한국어로 풀어 쓴 것입니다. 원문은 docs.openclaw.ai에서 보실 수 있어요. 제가 특정 구성에서 직접 측정하거나 우회해 본 결과는 없습니다.

채널 허용 목록과는 다른 이야기입니다

먼저 이름이 겹쳐서 헷갈리는 걸 갈라놓고 갑니다. OpenClaw에는 "허용 목록"이 두 군데 있어요.

  • 채널 허용 목록: 누가 봇에게 말을 걸 수 있는지. Access groups 글에서 다룬 내용입니다.
  • exec 허용 목록: 에이전트가 어떤 실행 파일을 호스트에서 돌릴 수 있는지. 이 글에서 다룰 내용이에요.

앞쪽이 열려 있어도 뒤쪽이 닫혀 있으면 명령은 안 돌아갑니다. 반대도 마찬가지고요.

승인은 도구 정책 위에 얹히는 층입니다

문서가 못을 박아 둔 성질이 하나 있습니다. 승인은 도구 정책과 Elevated 게이팅 위에 쌓이고, 두 정책이 다를 때는 더 엄격한 쪽이 적용됩니다. 승인 설정으로 설정 파일의 보안 수준을 느슨하게 만들 수는 없어요. 조일 수만 있습니다.

그래서 "설정 파일에 full이라고 적었는데 왜 계속 물어보나" 같은 상황이 생깁니다. 실행이 일어나는 그 기계의 승인 문서에 ask: "always"가 남아 있으면 계속 물어봅니다. 세션 기본값이나 설정 기본값이 뭐라고 하든 상관없어요. 승인 문서가 아예 없는 노드는 게이트웨이와 같은 full / off 기본선을 씁니다.

샌드박스와 도구 정책, Elevated를 아직 구분하지 않으셨다면 도구가 막힐 때 세 층을 나누는 글을 먼저 보시는 편이 낫습니다. 이 글은 그 위에 한 층을 더 올리는 이야기예요.

승인은 '실행이 일어나는 기계'에서 판정합니다

승인을 강제하는 곳은 명령이 실제로 돌아가는 호스트입니다.

  • 게이트웨이 호스트: 게이트웨이 기계의 openclaw 프로세스
  • 노드 호스트: 노드 러너, 즉 macOS 컴패니언 앱이나 헤드리스 노드 호스트

노드 실행은 보내기 전에 대상 정책을 한 번 더 확인합니다. 부르는 쪽이 allowlist나 off면 매칭 안 되는 명령은 거기서 막히고, 대상 쪽이 ask: "always"면 부르는 쪽이 full을 요청해도 승인을 받아야 해요. 노드를 아직 안 붙여 보셨으면 노드 권한이 열리는 순서 글이 짝이 됩니다.

macOS는 역할이 한 번 더 쪼개집니다. 노드 호스트 서비스가 system.run을 로컬 IPC로 macOS 앱에 넘기고, 승인 판정과 실제 실행은 앱이 UI 맥락에서 합니다.

신뢰 모델에서 문서가 분명히 선을 그은 문장도 옮겨 둘 만합니다. 승인은 실수로 실행되는 위험을 줄이는 장치이고, 사용자별 인증 경계나 읽기 전용 파일시스템 정책이 아닙니다. 한 번 승인된 명령은 호스트나 샌드박스가 허용하는 범위에서 파일을 고칠 수 있어요.

모드 다섯 개만 외워도 절반은 됩니다

tools.exec.mode가 호스트 exec의 기본 정책 표면입니다.

값 동작
deny 호스트 exec를 막습니다
allowlist 허용 목록에 있는 명령만, 묻지 않고 실행합니다
ask 허용 목록을 쓰고, 빗나가면 사람에게 묻습니다
auto 확정적으로 매칭되면 바로 돌리고, 빗나간 것 중 자격이 되는 건 리뷰어가 allow·deny·ask로 판정합니다
full 보통의 정책 프롬프트 없이 돌립니다

여기서 auto가 조금 새로운 방식이에요. 빗나간 명령을 사람에게 바로 던지지 않고, 리뷰어가 한 번 판정합니다. 위험이 낮거나 중간인 실행 한 번을 허가하거나, 거절 이유를 에이전트에게 돌려주거나, 사람에게 묻는 세 갈래입니다.

구식 설정을 쓰고 계시면 exec.security와 exec.ask 두 값이 따로 있습니다. security는 deny / allowlist / full이고 게이트웨이·노드 호스트의 기본값은 full, 샌드박스 호스트는 deny예요. ask는 off / on-miss / always이고 기본값은 off입니다. Doctor가 지원되는 짝을 mode로 옮겨 주는데, ask: "always"처럼 정확히 대응되는 mode가 없는 조합은 옛 필드를 그대로 두고 그 객체에서 mode를 빼야 정책이 유지됩니다.

ask: "always"의 성질도 알아 둘 만합니다. 이 상태에서는 예전에 "항상 허용"을 눌러 만들어 둔 항구적 신뢰가 프롬프트를 없애 주지 않습니다. 매번 묻습니다.

승인 창을 띄울 수 없을 때가 진짜 갈림길입니다

물어봐야 하는데 물어볼 화면이 없으면 어떻게 되나. 이걸 정하는 값이 askFallback이고 기본값은 deny입니다. 생략하면 막힙니다.

  • deny: 막습니다
  • allowlist: 허용 목록에 있으면 돌립니다
  • full: 활성 보안 정책에 더 엄격한 제한을 추가하지 않습니다. 허용 목록 제한과 명시적 승인이 필요한 형태는 그대로 남아요

이게 왜 중요한가 하면, 새벽에 도는 예약 작업이 조용히 실패하는 흔한 이유가 여기라서입니다. 사람이 승인창을 볼 수 없는 시간대에 기본값 deny가 그대로 작동한 거예요.

허용 목록은 에이전트별이고, 이름만 적으면 PATH 경유만 걸립니다

허용 목록은 에이전트 단위로 따로 관리됩니다. 한 에이전트에서 승인한 게 다른 에이전트로 새지 않아요. 패턴은 glob 매칭이고, 두 가지 형태를 씁니다.

  • 경로 glob: /opt/homebrew/bin/rg, ~/.local/bin/*
  • 맨 이름 glob: rg

맨 이름은 PATH를 거쳐 호출된 명령만 매칭됩니다. 그래서 rg라고 적으면 /opt/homebrew/bin/rg는 걸리지만 ./rg나 /tmp/rg는 안 걸려요. 특정 위치의 바이너리 하나만 믿고 싶으면 경로 glob을 쓰는 편입니다.

인수 모양까지 조이고 싶으면 argPattern을 붙입니다. 자바스크립트 정규식 문법을 쓰고, 실행 파일 토큰은 빼고 파싱된 인수에 대해 평가합니다. 손으로 쓴 항목은 인수가 공백 하나로 이어지니까 정확히 맞추려면 앵커를 거세요.

{
  "pattern": "python3",
  "argPattern": "^safe\\.py$"
}

이렇게 적으면 python3 safe.py만 통과하고 python3 other.py는 빗나갑니다. 다만 같은 바이너리에 대한 경로 전용 항목이 같이 있으면, 인수가 안 맞아도 그쪽으로 넘어가서 통과할 수 있어요. 인수까지 묶어 두려면 경로 전용 항목을 지워야 합니다.

'항상 허용'은 명령과 디렉터리에 묶입니다

승인 창에서 "여기서는 항상 허용"을 누르면 항목이 자동으로 생기는데, 이 항목은 정확한 argv와 승인한 작업 디렉터리 양쪽에 묶입니다. 같은 명령을 다른 디렉터리에서 돌리면 허용 목록 빗나감으로 처리돼요.

2026.8.1 이전에 생긴 항목은 디렉터리에 묶이지 않았고, 업그레이드 후에는 작동하지 않습니다. openclaw update가 자동 Doctor 단계에서 지우거나, openclaw doctor --fix를 직접 돌려도 됩니다. 그다음에 같은 작업을 다시 돌려서 "여기서는 항상 허용"을 한 번 더 눌러 대체 항목을 만드는 순서입니다. 손으로 적어 둔 규칙은 건드리지 않아요.

승인한 뒤에 파일이 바뀌면 실행하지 않습니다

문서에서 제가 제일 흥미롭게 읽은 부분입니다. 승인은 "이 명령"이 아니라 "이 실행 파일 신원"에 대해 내려집니다.

게이트웨이 승인 기반 명령은 검토 전에 모든 명령 세그먼트의 실행 파일을 바인딩하고, 실행 직전에 다시 확인합니다. 노드 호스트는 로컬 정책 평가 때 신원을 잡아 두고 보내기 전에 다시 확인해요. 바인딩된 구간에 해상도가 달라지면, 그러니까 PATH 앞쪽에 새 실행 파일이 끼어들기만 해도 실행을 거부합니다. 보호된 실행 파일은 실제 경로 신원만 쓰고, 쓰기 가능한 실행 파일은 내용 해시까지 씁니다.

셸 스크립트나 인터프리터로 파일을 직접 돌리는 형태면 구체적인 로컬 파일 피연산자 하나까지 묶어 보려고 합니다. 승인 뒤 실행 전에 그 파일이 바뀌면 바뀐 내용을 돌리지 않고 거부해요. 다만 문서는 이 파일 바인딩이 최선 노력이고 모든 로더 경로를 다 모델링한 게 아니라고 적어 뒀습니다. 구체적인 로컬 파일 하나를 특정할 수 없으면, 다 커버하는 척하지 않고 승인 기반 실행을 아예 만들지 않습니다.

사람이 원격에서 승인을 누르기까지 기다리는 사이의 셸 내부 실행 파일은 이 보호 범위에 들어가지 않는다는 단서도 같이 적혀 있어요.

python -c 한 줄이 따로 취급되는 이유

인터프리터를 허용 목록에 넣으면 구멍이 하나 생깁니다. python3를 믿기로 하면 python3 -c "무엇이든"도 같이 열리거든요. 그 한 줄짜리 코드는 파일이 아니라서 위에서 본 파일 바인딩이 걸리지 않습니다.

tools.exec.strictInlineEval을 true로 하면 이런 인라인 코드 실행 형태를 승인 전용으로 취급합니다. 보통의 full / off 정책이거나 인터프리터 바이너리가 허용 목록에 있어도 그래요. 문서가 잡아낸다고 적은 예시는 이렇습니다.

  • python -c, node -e / --eval / -p, ruby -e, perl -e / -E, php -r, lua -e, osascript -e
  • awk, sed, make, find -exec, xargs의 인라인 형태

이 경로에서는 리뷰어나 사람의 명시적 승인이 필요합니다. POSIX 로그인 셸이나 대화형 셸 래퍼는 리뷰어를 건너뛰고 사람 승인으로 갑니다. 시작 파일이 피연산자 바인딩 밖에 있어서라고 적혀 있어요. 그리고 인라인 코드 명령에 대해서는 allow-always가 새 허용 목록 항목을 남기지 않습니다.

기본값은 false입니다. 인터프리터를 허용 목록에 넣을 생각이라면 이 값을 켜는 쪽을 먼저 보시는 편이 낫겠다는 게 제 판단이고, 문서가 정한 기본값은 아닙니다.

safeBins는 '입력 스트림만 만지는' 좁은 통로입니다

tools.exec.safeBins는 허용 목록 항목 없이도 allowlist 모드에서 돌 수 있는 표준 입력 전용 바이너리 이름입니다. 위치 파일 인수와 경로처럼 보이는 토큰을 거부해서, 들어오는 스트림만 다룰 수 있게 해 둔 구조예요.

기본값으로 들어 있는 건 여섯 개입니다. cut, uniq, head, tail, tr, wc. grep과 sort는 기본 목록에 없습니다. grep을 넣으실 거면 패턴을 -e / --regexp로 주셔야 해요. 위치 인수 형태는 파일을 몰래 끼워 넣을 수 있어서 거부됩니다.

절대 넣지 말라고 문서가 경고한 것들도 분명합니다. python3, node, ruby, bash, sh, zsh처럼 코드를 평가하거나 하위 명령을 돌리거나 설계상 파일을 읽는 바이너리는 safeBins가 아니라 명시적 허용 목록 항목으로 다뤄야 합니다. awk, sed, jq는 아예 항상 거부됩니다. 스트림 전용임을 검증할 수 없는 의미 구조라서고, jq는 환경 데이터를 읽고 모듈이나 시작 파일에서 jq 코드를 불러올 수 있다고 적혀 있어요.

검증 방식도 성질이 있습니다. argv 모양만 보고 확정적으로 판정하고, 호스트 파일시스템 존재 확인은 하지 않습니다. 허용과 거부의 차이로 파일이 있는지 없는지를 알아내는 걸 막기 위해서예요. 긴 옵션은 실패 시 닫는 방향으로 검증하고, 모르는 플래그나 애매한 축약은 거부합니다. safeBins 구간의 argv 토큰은 실행 시점에 글자 그대로 다룹니다. glob 확장도 $VARS 확장도 없어서 *나 $HOME/...으로 파일 읽기를 끼워 넣을 수 없습니다.

실행 파일 위치도 걸립니다. safeBins는 신뢰된 바이너리 디렉터리에서 해석돼야 하고, 기본값은 /bin과 /usr/bin 둘뿐이에요. PATH 항목은 자동으로 신뢰되지 않습니다. /opt/homebrew/bin이나 /usr/local/bin에 있는 실행 파일을 쓰시려면 tools.exec.safeBinTrustedDirs에 직접 넣어야 합니다.

셸 체이닝은 모든 조각이 통과해야 합니다

&&, ||, ;로 이은 명령은 최상위 세그먼트 전부가 허용 목록 규칙을 만족할 때만 돌아갑니다. echo ok && pwd도 둘 다 걸려야 해요.

허용 목록 모드에서 안 되는 것들도 정리해 두면 이렇습니다.

  • 리다이렉션은 지원되지 않습니다
  • 명령 치환($(), 백틱)은 허용 목록 파싱 중 거부됩니다. 큰따옴표 안이어도 거부돼요. 글자 그대로의 $() 텍스트가 필요하면 작은따옴표를 쓰세요
  • macOS 컴패니언 앱 승인에서는 셸 제어·확장 문법이 들어 있는 원시 셸 텍스트를 허용 목록 빗나감으로 취급합니다. 셸 바이너리 자체가 허용 목록에 있을 때만 예외입니다

셸 래퍼(bash|sh|zsh ... -c 계열)에서는 요청 범위 환경 변수 재정의가 TERM, LANG, LC_*, COLORTERM, NO_COLOR, FORCE_COLOR로 줄어듭니다. env, flock, nice, nohup, stdbuf, timeout처럼 그냥 넘겨 주는 래퍼는 allow-always 때 래퍼 경로가 아니라 안쪽 실행 파일 경로를 저장합니다. 안전하게 벗겨낼 수 없으면 허용 목록 항목을 자동으로 남기지 않아요.

스킬이 부르는 실행 파일을 자동으로 믿는 옵션

autoAllowSkills를 켜면 알려진 스킬이 참조하는 실행 파일을 노드에서 허용 목록에 있는 것처럼 다룹니다. 게이트웨이 RPC로 skills.bins 목록을 받아 오는 구조예요. 스킬 글에서 다룬 그 스킬 파일들이 여기로 연결됩니다.

이건 손으로 적은 경로 허용 목록과는 별개인 암묵적 편의 목록입니다. 게이트웨이와 노드가 같은 신뢰 경계 안에 있는 운영 환경을 전제로 한 기능이고, 명시적 신뢰만 쓰시려면 autoAllowSkills: false로 두고 경로 항목만 쓰는 쪽입니다.

스킬 신뢰는 그 스킬을 준 게이트웨이에 속합니다. 게이트웨이를 바꾸면 이전 캐시는 은퇴하고, Mac 앱의 신뢰된 바이너리 목록과 진행 중인 승인 확인까지 함께 물러납니다. 갱신이 실패하면 같은 게이트웨이에서 마지막으로 알던 신뢰를 유지할 수 있지만, 다른 게이트웨이의 신뢰를 가져오지는 못합니다.

예약 작업 승인은 채팅으로 안 갑니다

여기가 자동화를 돌리는 분들에게 제일 실용적인 부분입니다. cron 같은 게이트웨이 호스트 자동화가 올린 승인은 연결된 exec 승인 클라이언트에게만 전달됩니다. Control UI, macOS·iOS·Android 앱, 그리고 approvals 또는 exec-approvals 능력을 선언한 API 클라이언트요.

터미널 UI는 exec 승인 카드를 그리지 않고, 채팅 채널은 자동화 승인을 절대 받지 않습니다. 매 실행마다 같은 카드가 반복될 테니까요. 리뷰어 화면이 하나라도 붙어 있으면 예약 실행은 대화형 실행처럼 결정을 기다립니다. 승인 화면이 하나도 없으면 요청은 즉시 거부되고, 실행 오류에 정책을 어떻게 고치면 되는지가 담깁니다.

자동화 실행에서 올라온 승인을 "항상 허용"으로 풀면 JSON 허용 목록 항목이 생기지 않습니다. 대신 게이트웨이가 범위가 한정된 상시 허가(standing grant)를 만듭니다. 정확히 그 에이전트, 그 자동화, 그 작업 설정, 그 작업 내용(명령 텍스트, 작업 디렉터리, 요청된 환경)에 묶여요. 승인 카드에 "항상 허용을 누르면 무엇이 만들어지는지"가 미리 적혀 나옵니다.

이 허가가 풀리는 조건이 촘촘합니다.

  • 작업을 고쳤거나 지웠을 때. 설정이 한 글자라도 바뀌면 무효입니다
  • 명령, 작업 디렉터리, 환경이 1바이트라도 다를 때
  • 허가가 취소되거나 만료됐을 때
  • 원래 승인 기록이 사라졌을 때

확인은 프로세스가 생성되기 바로 직전에 돌아갑니다. 그래서 실행 도중에 취소나 작업 수정이 들어와도 그쪽이 먼저 적용됩니다. 변경 가능한 파일 피연산자, 히어독, strict 인라인 eval, 감사 억제처럼 명시적 검토가 필요한 명령은 매번 다시 묻습니다.

수명은 기본적으로 취소할 때까지입니다. tools.exec.grantExpiryDays로 앞으로 만들어질 허가의 기본 수명을 일 단위로 정할 수 있고, 이미 만들어진 허가는 만들어질 때의 조건을 그대로 유지합니다. 먼저 은퇴시키려면 취소를 쓰는 거예요. 만료된 허가는 다시 묻는 쪽으로 돌아가고 기회가 될 때 정리됩니다.

허가는 전부 보이고 전부 취소할 수 있습니다. Control UI의 설정 → Approvals에 자동화, 정확한 명령, 사용 횟수, 상태가 나오고 행마다 취소 동작이 붙습니다. CLI로는 openclaw approvals grants list와 openclaw approvals grants revoke <grant-id>입니다. 취소는 여러 번 해도 같고, 다음 실행의 프로세스 생성 경계에서 효력이 생겨요.

채팅으로 승인을 받는 설정

exec 승인 프롬프트를 채팅 채널로 넘겨서 /approve로 처리할 수도 있습니다. 보통의 발신 전달 파이프라인을 그대로 씁니다.

/approve <id> allow-once
/approve <id> allow-always
/approve <id> deny

문서가 분명히 적어 둔 성질이 있어요. 맨 /approve나 지어낸 ID로는 승인이 되지 않습니다. 실제로 대기 중인 승인의 정확한 요청 ID가 있어야 합니다. 그리고 allow-once는 그 명령 하나만 덮습니다. 다음 명령은 자기 몫의 정책 판정을 따로 받아요.

설정은 approvals.exec 아래에 있고 enabled, mode(session / targets / both), agentFilter, sessionFilter, targets를 씁니다. 플러그인 승인은 approvals.plugin으로 완전히 따로 관리되고, 한쪽을 켜거나 끄는 게 다른 쪽에 영향을 주지 않습니다.

텔레그램처럼 포럼 주제가 있는 채널이면 targets에 accountId와 threadId를 붙일 수 있습니다. accountId는 여러 봇 계정 중 어느 계정으로 나갈지를 고르고, threadId는 최상위 채팅이 아니라 그 주제 안에 머물게 합니다. 채널 라우팅 글에서 본 목적지 개념이 승인 카드에도 같은 방식으로 적용되는 거예요.

그 방에 있는 사람 아무나 승인할 수 있는 건 아닙니다

이걸 문서가 FAQ로 따로 떼어 놨습니다. 세션 전달은 프롬프트가 어디에 보일지만 정하고, 그 자체로 그 방의 모든 참가자에게 승인 권한을 주지 않습니다.

일반적인 같은 방 /approve는 보낸 사람이 그 채널 세션에서 이미 명령 권한을 가지고 있어야 합니다. 채널이 명시적인 승인자 목록을 노출하면, 그 승인자들은 세션에서 명령 권한이 없어도 승인 동작을 할 수 있어요.

더 엄격한 채널도 있습니다. 디스코드, 텔레그램, Matrix, Slack 네이티브 승인 DM 같은 네이티브 승인 클라이언트는 각자 해석한 승인자 목록을 씁니다. 텔레그램 포럼 주제의 승인 프롬프트가 그 주제의 모두에게 보일 수는 있지만, channels.telegram.execApprovals.approvers나 commands.ownerAllowFrom에서 해석된 숫자 사용자 ID만 승인하거나 거부할 수 있습니다.

다 열고 싶다면, 두 층을 다 열어야 합니다

프롬프트 없이 돌리는 구성을 문서는 YOLO 모드라고 부릅니다. 두 층을 모두 열어야 해요.

층 YOLO 설정
tools.exec.mode gateway / node에서 full
호스트 askFallback full

로컬 단축 명령도 있습니다.

openclaw exec-policy preset yolo

이 명령은 로컬 tools.exec.host/security/ask와 로컬 승인 파일 기본값을 함께 고치고, askFallback: "full"도 같이 넣습니다. 의도적으로 로컬 전용이에요. 게이트웨이나 노드 호스트의 승인을 원격에서 바꾸려면 openclaw approvals set --gateway나 openclaw approvals set --node <id|name|ip>를 씁니다. 다른 프리셋은 cautious(allowlist / on-miss / deny)와 deny-all입니다.

문서가 같이 구분해 둔 것도 옮겨 둡니다. tools.exec.host=auto는 exec가 어디서 도는지를 고르고, YOLO는 호스트 exec가 어떻게 승인되는지를 고릅니다. 그리고 YOLO는 설정된 정책 위에 명령 난독화 탐지나 스크립트 사전 검사 같은 별도 층을 얹어 주지 않아요.

OpenClaw가 관리하는 Claude 세션에서는 Claude Code를 default 권한 모드로 띄웁니다. 원시 백엔드 인수가 bypassPermissions를 요청해도 OpenClaw의 실효 exec 정책이 네이티브 도구 훅과 권한 요청을 통해 계속 권위를 갖습니다.

지금 상태부터 확인하는 게 순서입니다

설정을 바꾸기 전에 지금 무엇이 열려 있는지 읽는 명령이 따로 있습니다.

명령 보여 주는 것
openclaw approvals get (--gateway / --node <id|name|ip>) 요청된 정책, 호스트 정책 출처, 실효 결과
openclaw exec-policy show 로컬 기계의 병합된 뷰
openclaw exec-policy set / preset 로컬 요청 정책과 로컬 호스트 승인 문서를 한 번에 맞춥니다

세션별 /exec 재정의는 여기에 안 나옵니다. 그 세션에서 /exec를 직접 돌려서 확인하는 게 맞아요. 로컬 범위가 host=node를 요청하면 exec-policy show는 그 범위를 런타임에 노드가 관리한다고 알려 줍니다. 로컬 승인 파일을 진실의 출처로 취급하지 않는다는 뜻입니다.

승인 데이터가 어디 있는지도 알아 두면 백업할 때 편합니다. 실행 호스트의 공유 SQLite 상태 DB 안이고, 기본 경로는 ~/.openclaw/state/openclaw.sqlite입니다. OPENCLAW_STATE_DIR을 설정하면 DB가 그 디렉터리를 따라갑니다. 상태 디렉터리는 서로 독립된 신뢰 범위라서, 다른 곳을 가리키면 기본 디렉터리의 승인을 가져오지도 보관하지도 않습니다. 커스텀 상태 디렉터리에는 승인을 따로 설정해야 해요.

정리

정리하면 순서는 이렇습니다.

  1. openclaw approvals get과 openclaw exec-policy show로 지금 상태를 읽습니다
  2. 모드를 allowlist나 ask 근처에 두고, 자주 쓰는 실행 파일만 경로 glob으로 넣습니다
  3. 인터프리터를 넣었다면 strictInlineEval을 검토합니다
  4. 예약 작업이 있으면 승인 화면이 없는 시간대에 askFallback이 어떻게 작동하는지 확인합니다
  5. 상시 허가 목록을 주기적으로 보면서 안 쓰는 건 취소합니다

문서가 마지막에 붙여 둔 문장도 옮겨 둘 만합니다. full은 강력하니 가능하면 허용 목록을 쓰라는 것, ask는 빠른 승인을 유지하면서 사람을 흐름 안에 남겨 둔다는 것, 에이전트별 허용 목록이 한 에이전트의 승인이 다른 에이전트로 새는 걸 막는다는 것입니다. exec를 확실히 막고 싶으면 승인 설정이 아니라 도구 정책에서 exec 도구 자체를 거부하는 쪽입니다.

위 내용은 모두 OpenClaw 공식 문서 tools/exec-approvals.md와 tools/exec-approvals-advanced.md에 적힌 것을 한국어로 풀어 쓴 것입니다. 원문은 docs.openclaw.ai에서 확인하실 수 있어요. 버전마다 기본값과 명령이 달라질 수 있으니 실제 동작은 쓰고 계신 버전에서 다시 보시는 편이 안전합니다. 제가 실제로 우회를 시도해 보거나 성능을 측정한 결과는 이 글에 없습니다.