Skip to content

fix(hook): find ask 게이트 우회와 tail 순열 미탐지를 고친다 - #362

Merged
ictechgy merged 6 commits into
mainfrom
fix/hook-review-followups
Sep 3, 2026
Merged

fix(hook): find ask 게이트 우회와 tail 순열 미탐지를 고친다#362
ictechgy merged 6 commits into
mainfrom
fix/hook-review-followups

Conversation

@ictechgy

@ictechgy ictechgy commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Bash 훅(3,304줄)과 편집 정책 두 파일을 --effort max 적대적 리뷰에 보낸 결과다. 리뷰가 낸 여섯 건을 전부 실측했고 사실인 셋만 고친다.

거짓으로 확인된 지적

리뷰가 critical 로 매긴 것이 거짓이었다.

_approved_runtime_executableshutil.which(name, path=os.defpath) 를 쓰는데 POSIX os.defpath":/bin:/usr/bin" 이고 선행 빈 항목은 현재 디렉터리를 뜻하므로, 적대적 저장소가 ./bash 를 심으면 훅이 그것을 실행한다.

Python 3.9.6 / 3.12.14 / 3.13.15 / 3.14.6  ->  os.defpath = '/bin:/usr/bin'

선행 콜론이 없다. ./env ./bash ./git 을 실제로 심고 확인했지만 전부 /usr/bin·/bin 으로 해석된다. 이 전제 위에 얹힌 S4.1(git 경로 문제)도 함께 무너진다.

git grep/git blame--no-textconv 를 거부할 것이라는 지적도 거짓이다. 셋 다 수용한다(blame 은 파일을 줘야 제대로 판별된다).

고친 것

1. find ask 게이트가 토큰 접합으로 뚫렸다

find . -name "*.env" -delete        -> ask    (전)
find . -name "*.env" -delete;true   -> 허용   (전)  ← 문제
find . -delete&&true                -> 허용   (전)  ← 문제

shlex 는 따옴표 밖의 ; 를 단어에 붙여 두므로 -delete;true 가 한 토큰이 되어 정확 일치를 빗나갔고, 이어서 MiniShell 이 ; 를 거부해 decline → 원본 그대로 실행됐다. 설계 주석은 이 게이트가 "파싱과 무관하게" 잡는다고 적어 두었지만 실제로는 구분자 의존적이었다. 문자 다섯 개로 제품에 남은 유일한 사용자 브레이크가 사라진다.

구분자를 떼어낸 조각으로도 본다. 공백류는 구분자에 넣지 않는다 — 처음에 개행까지 넣었더니 find . $\<개행>'-exec' … 가 ask 로 바뀌었는데, bash 는 그 줄 연결을 지워 $-exec 로 읽으므로 실제로는 -exec 를 실행하지 않는다. 없는 위험을 묻게 되는 오탐이었고 기존 테스트가 잡았다.

2. tail 옵션 순열을 보지 못했다

tail -f a.log        -> 통과   (전)
tail a.log -f        -> 래핑   (전)  ← 문제
tail a.log -n +1 -f  -> 래핑   (전)  ← 문제

GNU tail 은 옵션을 순열하는데 _head_tail_is_safe 는 첫 위치인자에서 훑기를 멈춘다. 래핑된 follower 는 끝나지 않아 600초 워치독까지 턴이 멈춘다. 같은 함정을 이 파일은 sed 와 shortlog 에서 이미 고쳤다(주석에 "GNU sed 는 옵션을 순열한다"고 적혀 있다). head/tail 만 빠져 있었다.

-- 뒤는 피연산자이므로 tail -- -f-f 는 파일 이름으로 두고, -fn 20 같은 묶음 옵션도 본다.

3. is_already_wrapped 가 항상 False 였다

classify_incoming_wrapper 가 한 번도 돌려주지 않는 "exact" 를 확인하고 있었다. 그 함수는 None, "incoming_wrapper_denied", "nested_wrapper_denied" 만 반환한다. 유일한 호출자가 assertFalse 라 그 사실이 드러나지 않았다.

판단하지 못한 것

리뷰의 S5(재귀 가드 우회)는 호스트 허용목록 동작에 달려 있어 이 패킷만으로 판단할 수 없다. 리뷰도 그렇게 밝혔다. 다만 가드가 자기 주석이 말하는 불변식보다 좁은 부분집합만 강제하는 것은 코드에서 확인된다. 별도 조사가 필요하다.

Gate-B gen21

다시 B2 의 rewrite_bash_for_token_budget.py 와 미러를 바꾸므로 gen17 이후와 같은 절차를 따른다. 경로 집합은 좁히지 않는다. 네 커밋 왕복 후 최종 트리가 원래와 동일함을 확인했고, 지문은 생산 canonicalizer 로 계산했다.

증거

tests.test_context_guard_shell_contract 93건, tests.test_gate_b_rollback_proof 73건 통과. 신규 회귀 테스트 5건 — 접합 형태 ask, 삭제처럼 보이는 무해한 명령은 ask 아님, follow 옵션 위치 무관 비래핑, 정상 head/tail 은 계속 래핑, is_already_wrapped 의 True/False 양쪽.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YZWGDQsVTLjsBogUSrmnzH

ictechgy and others added 6 commits September 3, 2026 15:02
리뷰가 낸 여섯 건 중 실측으로 사실이 확인된 셋만 고친다. "critical" 로 매겨진
os.defpath 가 CWD 를 먼저 뒤진다는 지적은 거짓이었다 - Python 3.9/3.12/3.13/3.14
모두 '/bin:/usr/bin' 이고 선행 콜론이 없다. ./bash 를 심고 실제로 확인했다.
git grep/blame 이 --no-textconv 를 거부한다는 지적도 거짓이다. 셋 다 수용한다.

- find ask 게이트가 토큰 접합으로 뚫렸다. shlex 는 따옴표 밖의 `;` 를 단어에
  붙여 두므로 `find . -delete;true` 가 `-delete;true` 한 토큰이 되어 정확
  일치를 빗나갔고, 이어서 MiniShell 이 `;` 를 거부해 통과시켰다. 문자 다섯
  개로 제품에 남은 유일한 사용자 브레이크가 사라졌다. 구분자를 떼어낸 조각으로도
  본다. 이 게이트의 취지가 파싱 성공 여부와 무관하게 되돌릴 수 없는 삭제를
  사람에게 묻는 것이므로 여기가 맞는 자리다.

  구분자에 공백류는 넣지 않는다. 처음에 개행까지 넣었더니
  `find . $\<개행>'-exec' …` 가 ask 로 바뀌었는데, bash 는 그 줄 연결을 지워
  `$-exec` 로 읽으므로 실제로는 -exec 를 실행하지 않는다. 없는 위험을 묻게
  되는 오탐이었고 기존 테스트가 잡았다.

- tail 옵션 순열을 보지 못했다. GNU tail 은 옵션을 순열하는데 _head_tail_is_safe
  는 첫 위치인자에서 훑기를 멈춰 `tail a.log -f` 를 안전으로 판정했다. 래핑된
  follower 는 끝나지 않아 워치독까지 턴이 멈춘다. 같은 함정을 이 파일은 sed 와
  shortlog 에서 이미 고쳤고 head/tail 만 빠져 있었다. `--` 뒤는 피연산자이므로
  `tail -- -f` 의 -f 는 파일 이름으로 두고, `-fn 20` 같은 묶음 옵션도 본다.

- is_already_wrapped 가 항상 False 였다. classify_incoming_wrapper 가 한 번도
  돌려주지 않는 "exact" 를 확인하고 있었다. 유일한 호출자가 assertFalse 라 그
  사실이 드러나지 않았다. 분류기가 봉투로 인정한 것을 인정하게 하고, True 가
  되어야 하는 입력을 테스트에 함께 고정해 다시 죽으면 실패하게 했다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZWGDQsVTLjsBogUSrmnzH
Bash 훅의 find ask 게이트·tail 순열·죽은 헬퍼 수정이 다시 B2 의
rewrite_bash_for_token_budget.py 와 그 미러를 바꾼다. gen17 이후와 같은 이유로
freeze 가 실제 blocker 이고, 같은 이유로 경로 집합을 좁히지 않는다.

지문은 생산 canonicalizer 로 계산했다. 기존 레코드와 지문은 건드리지 않았다.
세대 목록 핀과 narrowed_paths_report 기대값을 gen21 까지 늘린다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZWGDQsVTLjsBogUSrmnzH
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: da727792-232c-4139-8180-c23ced73d32d


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ictechgy
ictechgy merged commit 20d1835 into main Sep 3, 2026
6 checks passed
@ictechgy ictechgy mentioned this pull request Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant