Repository navigation
보안 감사 심각 항목 일곱 건 수정 - #7
Merged
Merged
Conversation
- CRLF 쌍이 아닌 개행과 제어문자와 obs-fold 와 중복 Host 를 400 으로 거부 - 버전 문자열은 알려진 두 값만 받고 호스트는 ASCII 만 통과 - 거부된 요청은 업스트림에 접속하지 않고 결과를 기록하지 않음 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
- 상대 심볼릭 링크 대상을 어휘적 부모가 아닌 해소된 부모에 붙임 - macOS 에서 `/System/Volumes/Data` 표기를 firmlink 표 기준으로 루트 표기로 접음 - 요청 경로와 규칙 경로에 같이 적용하며 정책 다이제스트는 바뀌지 않음 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
- `(remote unix)` 통째 허용 대신 mDNSResponder 와 syslog 리터럴만 방출 - 자식 환경에서 `SSH_AUTH_SOCK` 과 `DOCKER_HOST` 를 벗김 - 배너와 gap 에 남는 허용 목록을 드러냄 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
- seccomp 가 모든 중재 수준에서 ioctl TIOCSTI 와 TIOCLINUX 를 EPERM 으로 거부 - `--mediate full` 이 rename 과 link 계열을 원본 delete 와 목적지 create 로 중계 - dirfd 를 커널과 같이 하위 32비트로 읽고 기준을 못 찾으면 거부 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
- 재앵커링과 앵커 뒤 엔트리와 `session_end` 뒤 엔트리를 검증 실패로 올림 - 앵커된 세션의 `head.json` 뒤처짐은 fsync 를 끈 경우만 경고로 남김 - `airlock audit verify` 와 `report` 가 새 실패를 증거 이상으로 보고 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
- `airlock run` 이 처음 보거나 바뀐 정책을 `/dev/tty` 로 확인받고 터미널이 없으면 78 로 거부 - `--yes` 와 `--observe` 로 건너뛸 수 없음 - `airlock policy trust` 신설과 `setup` 이 만든 파일 자동 기록 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
2026년 9월 보안 감사에서 "심각" 으로 분류된 일곱 항목을 닫습니다. 감사는 docs/limitations.md 에 이미 적힌 한계를 제외하고 새로 드러난 것만 셌으며, 일곱 건 중 다섯은 이 Mac 에서 재현했고 둘은 Linux 전용이라 코드로 확인했습니다. 저장소가 "닫혀 있다" 고 약속했으나 실제로는 열려 있던 지점들입니다.
닫은 것
macOS 프록시 모드의 유닉스 도메인 소켓. 프로파일이 (allow network-outbound (remote unix)) 를 무조건 방출해서 샌드박스 안 프로세스가 바깥의 유닉스 소켓 리스너로 데이터를 내보내고, 상속된 SSH_AUTH_SOCK 으로 ssh-agent 에 서명을 요청할 수 있었습니다. docker.sock 이 살아 있는 호스트라면 컨테이너 데몬에 그대로 닿습니다. 전부 프록시도 감사 로그도 거치지 않았습니다. 이제 /private/var/run/mDNSResponder 와 /private/var/run/syslog 리터럴 두 개만 열고 그 목록을 배너와 gap 에 드러냅니다. 자식 환경에서 SSH_AUTH_SOCK 과 DOCKER_HOST 를 벗깁니다. 실제 Seatbelt 아래에서 바깥 리스너 접속이 거부되는 통합 테스트로 고정했습니다.
앵커 재앵커링. 같은 세션의 두 번째 앵커 줄이 경고로만 남았습니다. 브로커는 세션당 앵커를 한 번만 쓰므로 이 허용은 순수한 공격 표면이었고, chain.jsonl 과 anchors.jsonl 에 append 만 할 수 있는 공격자가 종료된 세션에 엔트리를 덧붙이고 새 head 를 잇는 앵커 한 줄을 더하면 verify 는 0 을, report 는 clean 을 냈습니다. 세션당 앵커는 정확히 하나이며 초과는 실패입니다. 앵커 뒤 엔트리, session_end 뒤 엔트리, 앵커된 세션의 head.json 뒤처짐이 전부 검증 실패와 증거 이상이 됩니다. head.json 뒤처짐은 fsync_per_entry 를 끈 세션만 예외인데, 그 경우에만 크래시로 그 상태가 정상적으로 생길 수 있기 때문입니다.
상대 심볼릭 링크 해소. 링크 대상이 상대 경로면 어휘적 부모에 붙였습니다. 심볼릭 링크된 디렉토리 아래의 x -> ../id_rsa 를 커널은 링크 대상 쪽 파일로 여는데 엔진은 작업 공간 안 경로로 계산해 작업 공간 규칙으로 허용했습니다. 상대 대상을 해소된 부모에 붙이고 매달린 링크도 같은 기준으로 계산합니다. explain 으로 확인하면 같은 요청이 allow 에서 deny 로 바뀝니다.
프록시 평문 전달 경로의 bare-LF 스머글링. 헤드를 CRLF 로만 잘라 줄 안의 LF 가 값에 남았고 그것이 업스트림에 그대로 재조립되어 두 번째 Host 를 심을 수 있었습니다. CRLF 쌍이 아닌 CR 과 LF, 헤더 값의 제어문자, obs-fold, 중복 Host, HTTP/1.0 과 HTTP/1.1 이외의 버전, 비ASCII 호스트를 판정 전에 400 으로 거부합니다. 거부된 요청은 업스트림에 접속하지 않고 결과 엔트리를 남기지 않으며, 그 세 가지가 한 헬퍼로 함께 단정됩니다.
macOS /System/Volumes/Data 표기. firmlink 때문에 같은 파일의 두 번째 철자가 자기보호와 ~/.ssh/** forbid 를 포함한 전 티어에 매칭하지 않았습니다. 커널 Seatbelt 는 막았지만 정책 판정, explain, observe 모드, 감사 귀속이 틀렸습니다. /usr/share/firmlinks 표에 있는 대상을 루트 표기로 접으며, 표를 읽지 못하면 내장 목록으로 내려갑니다. 요청 경로와 규칙 경로에 같이 적용하므로 두 철자가 하나로 수렴하고, 정책 다이제스트는 바뀌지 않습니다.
Linux TIOCSTI 승인 위조. 자식은 제어 터미널을 상속받고 승인 프롬프트는 /dev/tty 에서 답을 읽으므로 자식이 ioctl(TIOCSTI, "y\n") 으로 승인을 위조할 수 있었습니다. macOS 는 Seatbelt 가 이미 거부함을 실측했고 Linux 는 커널 설정에 따라 갈립니다. seccomp 필터가 모든 중계 수준(off 포함)에서 TIOCSTI 와 TIOCLINUX 를 EPERM 으로 거부합니다. bubblewrap 과 flatpak 이 같은 조치를 합니다. cBPF 조립을 순수 모듈로 분리해 macOS 에서도 작은 해석기로 결과값을 검증합니다.
Linux 정책 파일 심기. Landlock 은 inode 기반이라 아직 없는 경로의 생성을 거부할 수 없고 작업 공간 루트에 통째 허용을 주므로, 샌드박스 안 에이전트가 ./airlock.toml 을 만들거나 같은 디렉토리 안 rename 으로 기존 파일을 갈아 끼울 수 있었습니다. 다음 airlock run 은 그 파일을 홈 정책보다 먼저 읽습니다. 방어는 두 겹입니다. --mediate full 이 rename 과 link 계열 일곱 syscall 을 원본 delete 와 목적지 create 로 중계해 자기보호 규칙에 걸리게 하고, 로드 시점에 정책 다이제스트를 감사 루트 아래 신뢰 기록과 대조합니다.
설계 결정
정책 파일 신뢰 기록(TOFU). 작업 공간 루트를 Partial 로 내리면 루트에 새 파일을 만들 수 없어 실사용이 깨지므로 커널 층이 아니라 로드 시점에 막습니다. airlock run 이 정책 파일을 읽을 때마다 정책 다이제스트를 감사루트/trusted-policies.jsonl 과 대조하고, 처음 보거나 바뀐 정책은 /dev/tty 에서 한 번 확인을 받습니다. 터미널이 없으면 종료 코드 78 로 거부하며 --yes 와 --observe 로 건너뛸 수 없습니다. 에이전트가 심은 정책이 바로 --yes 실행에서 읽히는 시나리오가 이 기능이 막으려는 것이기 때문입니다. airlock policy trust [PATH] [--list] 가 신설되었고 airlock setup 이 만든 파일은 자동으로 기록됩니다. 기록 파일은 감사 루트의 자기보호에 기대며, direnv allow 와 같은 모델입니다. 근거는 docs/design.md 9.6 입니다.
심볼릭 링크 대상 문자열은 판정하지 않습니다. symlink 중계에서 링크가 가리키는 문자열은 접근이 아니라 값이고, delete 로 보면 venv 의 python 링크 생성 같은 정상 작업이 깨집니다. 링크를 통한 접근은 열릴 때 해소 경로로 판정됩니다.
mDNSResponder 소켓은 남깁니다. 이 소켓 없이는 getaddrinfo 가 전부 실패해 이름 해석이 깨집니다. 루트 소유 데몬이고 주는 능력은 이름 질의뿐이라 이미 선언된 DNS 반출 한계(limitations 4.1.1) 그대로이며 새 능력 상승이 없습니다.
검증
scripts/check.sh 가 전부 통과합니다. fmt 와 clippy 와 워크스페이스 테스트 682개, 라이브러리 unwrap 금지, 프리셋 여섯 벌, 배포 메타데이터, cargo deny 를 포함합니다. x86_64 와 aarch64 리눅스 타겟의 clippy 도 로컬에서 통과했습니다. 커밋 일곱 개는 각각 따로 컴파일되므로 bisect 가 깨지지 않습니다.
Linux 전용 테스트(TIOCSTI EPERM, rename 중계, 두 번째 seccomp 필터 설치)는 이 Mac 에서 컴파일과 린트까지만 확인했고 실제 실행은 CI 의 ubuntu 러너가 합니다.
문서
docs/design.md 에 9.6 정책 출처 신뢰 절을 신설하고 중계 층 표를 갱신했습니다. docs/limitations.md 에 3.15(Landlock 부재 경로) 를 신설하고 4.1, 4.5, 5.x, 6.3, 6.4, 6.12, 7.1, 7.11, 8.5, 9.6, 10.1, 10.2 를 갱신했습니다. docs/audit-format.md 8절의 "재앵커링 허용" 서술을 제거하고 9.2 에 kind 고정 표를 두었습니다. docs/egress-proxy.md 의 "프록시가 유일한 출구" 는 플랫폼과 조건을 명시한 문장으로 바꿨습니다. README 두 벌과 COMPLIANCE.md 의 정책 신뢰 서술도 맞췄습니다.
남은 것
감사에서 중간으로 분류된 아홉 건과 낮음 열두 건은 이 PR 에 없습니다. 목록은 CHANGELOG 가 아니라 감사 보고서에 있으며 후속으로 다룹니다.
이 PR은 Claude Fable 5.1로 작성되었습니다.