본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 06. 15. 07:43

Bash AST 기반으로 Coding Agent의 명령 실행을 검사하는 도구 「Vetol」을 만들었습니다

요약

Coding Agent가 실행하는 Bash 명령을 Bash AST(Abstract Syntax Tree) 기반으로 정밀하게 검사하는 도구인 Vetol을 소개합니다. 단순 패턴 매칭이나 정규 표현식의 한계를 넘어, 명령 치환이나 논리 연산자 내부에 숨겨진 명령까지 추출하여 허가 또는 거부할 수 있습니다.

핵심 포인트

  • Bash AST를 해석하여 복잡한 명령 구조 내의 개별 명령을 추출
  • 정규 표현식 기반 검사의 우회 가능성(bypass) 문제 해결
  • JSON 설정을 통한 allowlist 및 denylist 모드 지원
  • 명령 인자의 위치나 생략 표기법을 고려한 정밀한 규칙 적용 가능

개요

Coding Agent의 명령 실행을 Bash AST (Abstract Syntax Tree) 기반으로 검사하는 도구 「Vetol」을 만들었습니다.

이 명령으로 설치할 수 있습니다.

go install github.com/tf63/vetol/cmd/vetol@latest

배경

Coding Agent의 PreToolUse

Hook을 사용하면, 실행할 명령을 사전에 검사하여 허가할지 거부할지를 제어할 수 있습니다.

예를 들어, git push -f를 Prefix 기반의 패턴 매칭 git push -f *로 거부하면, Coding Agent에 의한 git push -f origin HEAD와 같은 명령의 실행을 거부할 수 있습니다.

하지만 Bash의 경우, 다음과 같은 명령은 쉽게 우회(bypass)됩니다.

git push -uf origin main
git push -u -f origin main
SAMPLE=1 git push -f origin main
pwd && git push -f origin main
echo $(git push -f origin main)

그 외에도, Claude Code의 PreToolUse 샘플에서는 명령을 검사하기 위해 단순한 정규 표현식(Regular Expression)을 사용하고 있습니다.

if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
...

하지만 이는 rm -fr 등이 실행되면 우회될 수 있습니다.

만든 것

그래서 만든 것이 Vetol입니다. Vetol은 Bash의 AST를 해석하여, 명령 치환(Command Substitution)이나 논리 연산자(&&, ||) 내부에 있는 명령도 추출할 수 있습니다.

예를 들어, 다음 명령으로부터는 다음과 같은 명령들을 추출하여 검사합니다.

echo `ls && rm -rf / || echo $(git push -f origin main)`

echo
ls
rm -rf /
echo
git push -f origin main

이 5개의 명령에 대해 allowlist 또는 denylist 모드의 규칙을 적용하여 허가/거부를 결정합니다.

규칙은 JSON 형식으로 지정합니다. allowlist 모드에서는 허가하고 싶은 명령을 지정하며, 그 외에는 모두 거부됩니다. 또한, include / exclude 필드를 사용하여 특정 플래그나 인자(Argument)가 있는 경우에만 허가/거부할 수도 있습니다.

{
"mode": "allowlist",
"rules": [
...

denylist 모드에서는 거부하고 싶은 명령을 지정하며, 그 외에는 모두 허가됩니다.

{
"mode": "denylist",
"rules": [
...

CLI에서 이 JSON을 지정하여 실행하면, 대상 명령이 허가되어 있을 때는 ALLOW, 거부되어 있을 때는 DENY가 출력됩니다.

vetol --config vetol.json "ls -la /tmp"
ALLOW # 상태 코드 0으로 종료
vetol --config vetol.json "rm -rf /"
DENY # 상태 코드 1로 종료

또한, include / exclude 필드는 명령 인자의 위치나 생략 표기법을 고려하여 검사됩니다. git pushinclude-f를 지정한 경우, 다음과 같은 명령들을 체크할 수 있습니다.

git push -f origin HEAD
git push -f -u origin HEAD
git push -uf origin HEAD
git push -u -f origin HEAD

이처럼 단순한 문자열 매칭으로는 놓치기 쉬운 명령도 Bash의 구문을 해석함으로써 검사할 수 있습니다.

Claude Code에서의 사용 예시

Claude Code에서 Vetol을 사용하는 경우, 다음과 같은 설정 파일을 작성하여 PreToolUse 훅에서 호출합니다.

// vetol.json
{
"mode": "allowlist",
...
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
...

주의사항

Vetol은 AST (Abstract Syntax Tree) 기반으로 명령어를 검사하기 때문에, 문자열을 eval 하여 실행하는 타입의 명령어구나 동적으로 생성되는 명령어는 탐지할 수 없습니다. 예를 들어, 다음과 같은 명령어들입니다.

bash -c "rm -rf /"
eval "git push -f origin main"
python -c "os.system('rm -rf /')"

이러한 경우에 대응하기 위해서는, denylist 모드에서 위험한 인터프리터 호출을 차단합니다.

{
"mode": "denylist",
"rules": [
...

또한, 예상치 못한 명령어가 실행될 가능성도 있으므로, allowlist 모드에서 필요한 명령어만 허용하는 것이 안전하다고 생각합니다.

{
"mode": "allowlist",
"rules": [{ "command": "ls" }, { "command": "git status" }, { "command": "go test" }]
...

마치며

Coding Agent의 권한 제어에서는 단순한 문자열 매칭이나 정규 표현식만으로는 불충분한 경우가 있습니다. Vetol은 Bash AST를 분석함으로써, 명령어 치환(Command Substitution)이나 논리 연산자 내부에 있는 명령어까지도 검사할 수 있도록 했습니다.

만약 개선점이나 버그 등이 있다면, GitHub 리포지토리에 Issue를 남겨주시면 감사하겠습니다. 또한, Star를 눌러주시면 큰 힘이 됩니다.

이상, 무엇인가 참고가 되기를 바랍니다.

Discussion

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0