# task-2612+3 — `_read_json` hard-link containment 우회(H1h) 봉합 결과 보고

- **상태**: `REMEDIATED_HARDENING_DONE_PENDING_INDEPENDENT_ANU_REAUDIT`
- **Executor**: dev4-team 비슈누 (key `7943afbe12c12f7d`) 1회 한정 — task-2612 계열 원 executor
- **분류**: AUTO_REMEDIATION_HOLD 자동 수렴 (non-Critical HIGH×1 · CRITICAL 0 · critical7 false) — 회장 확인 대기 0
- **실행 윈도(UTC)**: 시작 ≈ 2026-05-19T13:14:00Z (spec 무결성 검증) → 종료 2026-05-19T13:23:16Z (최종 해시/테스트 캡처)
- **spec 무결성**: `memory/tasks/task-2612+3.md` sha256 = `d4bf1b86a43316455dc6468ef4d2db3ebd5fc4229fdd735634ebe5cd0fde0211` — 위임 지정 타깃과 **일치 확인**, §1~§8 본문 정본 준수.

## 1. 잔여 HIGH (H1h) — 봉합 대상

`anu_v3/auto_remediation_planner.py` `_read_json` 의 containment 가 pathname-only.
`CANONICAL_WS_ROOT` 내부 쓰기권한 공격자가 동일 파일시스템·동일 uid 의
ws-밖 inode 에 대한 **hard link** 를 ws 내부 경로에 심으면: 그 in-root pathname 이
`_contained_resolved()` → `O_NOFOLLOW`(hard link≠symlink) → `/proc/self/fd`
realpath(hard link 별도 realpath 없음·in-root) → `fstat S_ISREG` 를 전부 통과한 뒤
fd 로 **ws-밖 inode 내용 read**(race 없는 out-of-scope read).
H1r(validate→open TOCTOU symlink-swap)는 task-2612+2 에서 **CLOSED 확정** —
잔여는 hard-link 동일-inode 벡터만.

## 2. 교정 (inode-수준 containment 강화 · additive defense-in-depth)

helper **1개** 추가: `_assert_fd_inode_contained(fd, resolved)` — `_read_json` 내
H1r `fstat S_ISREG` 검사와 `os.fdopen` 사이에 **3차 additive** 로 호출.

- `os.path.samestat(os.fstat(fd), os.lstat(resolved))` 동일성 대조 — 불일치 =
  check→open swap/우회 → `PathContainmentError` fail-closed (H1r realpath 검증과
  직교한 additive 보강).
- 정규파일 + `st_nlink > 1` → ws-밖 hard link 가능 → `PathContainmentError`
  fail-closed. 본 read-path 가 소비하는 정본 JSON(schema·adjudication·plan)은
  모두 단일-link(검증: nlink=1) → 무회귀.

**계층**: 1차 `_contained_resolved`(byte-0) | 2차 H1r `O_NOFOLLOW`+
`_fd_realpath`+`fstat S_ISREG`(byte-0·재변경 0·라인 무변) | 3차 H1h
`_assert_fd_inode_contained`(순수 additive 삽입). planner **산출 성격**
(plan 골격만·실 dispatch 0·실 코드수정 0) **불변** — plan-only AST 가드 PASS.

## 3. regression

- 기존 **31 케이스 전수 무회귀** (변경 전 31 passed → 변경 후에도 byte-0, 사전 케이스 무수정).
- additive **10 케이스**:
  - (a) ws-내부 hard-link → ws-밖 동일-inode 차단
  - (b) ws-내부 정규 단일-link read 무회귀 (격리 + 실 schema end-to-end)
  - samestat-mismatch 분기 직접 검증 + helper 단일-link PASS 무회귀
  - (c) H1r symlink-swap 차단 기존 케이스 전수 retained·PASS
  - (d) 2604/2605/2609 plan 변환 ×3 무회귀 (`validate_plan == []`)
  - (e) plan-only AST 가드 PASS additive + self-check invariants
- **합계 41 passed** (`41 passed in 0.31s`).
- `python -m anu_v3.auto_remediation_planner --self-check` → `all_passed=True`
  · `plan_only=True` · `dispatch_performed=False` · cases=3 **재현**.

## 4. 산출물 sha256 / invariants

- `anu_v3/auto_remediation_planner.py` → `c5d8353837e2e19724c910ca7b6f40f35228aaa27a42b3611cd9b20b1c028854`
- `tests/regression/test_auto_remediation_planner.py` → `81d0bfac1641a7f54da8a146f692570a70a06220ef2f410aff2feacb54a80938`
- schema `schemas/auto_remediation_plan.schema.json` → `272a6f415b0ddf00bf0c677c3e97691ce548bd8f5e12458053d58e249bc6f430` (**byte-0 무변**)
- H1r/H2/`_normalize_expected_rel`/skeleton: 라인 무변(additive 삽입만)
- git: HEAD `20456b5f83fc039f2fd6f50f4b94095c29b41bfb` · branch
  `task/task-2553p1-f1-clean-replacement` — **전후 EQUAL**(커밋 0·ANU Layer-A
  no-git·planner/test 파일은 untracked working-tree-only)
- write 범위: allowlist 한정. `memory/events/task-2612+3.decision.json` 은
  독립 ANU collector(key `c119085addb0f8b7`)의 **기존 dispatch 권위 산출물**
  → executor 미변조(§5 anti-tamper). 워크스페이스의 기존 다수 M/?? 파일은
  타 track baseline 으로 executor 비산출.

## 5. 투명성 플래그 (독립 ANU adjudication 회부)

`decision.json` 기록 `spec_sha256` = `7762ae8a07f685b29f789a9b9b9318b07641f440c961a3218954818c2224ef82`
이나, 실제 spec 파일 및 위임 지정 무결성 타깃은 모두
`d4bf1b86a43316455dc6468ef4d2db3ebd5fc4229fdd735634ebe5cd0fde0211`.
위임 지정 타깃이 파일과 일치하여 진행했으며, decision.json 해시 불일치를
**묵살하지 않고** 독립 ANU 판정으로 회부함.

## 6. callback & loop-boundary

- 완료 직후 normal completion callback 을 **독립 ANU key `c119085addb0f8b7`
  로만** 발사(+49 정본). executor self key `7943afbe12c12f7d` 절대 미사용.
- 본인 collector/adjudication/write-back/하류 dispatch·후속 cron 등록 **0** —
  독립 ANU 가 회수·Codex 재audit·adjudication·loop-boundary 판정·(조건부)
  +53 durable-success write-back 수행.
- **LOOP-BOUNDARY**(§6/§8): 본 라운드는 회장-인가 마지막 자동 수렴 라운드.
  +3 collector 가 동일 `_read_json`/동일 file-boundary 계열 non-Critical HIGH
  를 또 적출하면 단순 +4 금지 — 독립 ANU 가
  `AUTO_REMEDIATION_LOOP_BOUNDARY_REVIEW` 분류 + 회장 요약 보고.
  본 라운드 자체는 분류-후-멈춤 미적용(자동 수렴 완료).

## 7. 결론

H1h(hard-link 동일-inode out-of-scope read) 를 inode-수준 3차 additive
containment 으로 fail-closed 봉합. H1r/H2/schema/skeleton/plan-only invariant
및 git EQUAL 보존, 기존 31 + additive 10 = 41 regression 전수 PASS,
self-check 재현. status =
`REMEDIATED_HARDENING_DONE_PENDING_INDEPENDENT_ANU_REAUDIT` — 독립 ANU
재audit/adjudication 대기.
