KISA 제보 3건(KVE-2026-2010/2011/2018)과 그 동일 계열 형제 결함을 전수 조치하고,
그 과정에서 드러난 두 결함군을 함께 닫는다.
- 검증 시점과 연결 시점이 host 를 다르게 읽던 SSRF 통로를 정규화 SSoT 한 곳으로 모았다
- 세션을 여는 지점(2FA 완료·토큰 재발급)이 잠금 검사를 거치지 않아 계정 잠금이 우회됐다
- 인증도 서명도 없는 브라우저 리턴 콜백이 주문 상태를 바꾸던 통로를 4 PG 전부에서 닫고,
소유권을 대조하는 close-report 를 토스에도 신설했다. 그 결과 정리 주체를 잃는
결제창 미완료 주문은 만료 자동취소가 거둔다
- 저장소 A(_local)에만 쓰는 경로가 B 의 값을 조용히 덮던 회귀를 정본 writer 로 닫았다
(engine-v1.63.5). 한 방향만 보던 정적 검사에 반대 방향 축과 양방향 계약 테스트를 더했다
- 레이아웃 JSON 의 같은 객체 중복 키가 앞선 선언을 오류 없이 삼키던 결함군을 닫았다
확장 문서의 제품 호칭을 「그누보드7」로 통일했다. 가 지적한 두 문구는
개별 오타가 아니라 생성기가 찍는 정형 문구여서, 산출물이 아니라 방출 지점
세 곳을 먼저 고쳤다 — 그러지 않으면 21번째 확장부터 다시 샌다. 정리 범위는
확장 문서와 그 생성기까지이며, 코어 docs 와 언어팩 표시명은 의도적으로 남긴다.
레이아웃 편집기 대응 문서가 없던 문제는 확장마다 docs/editor-spec.md 를
두어 닫았다. 실측은 EditorSpecCollector 가 유지하며, 합본에 런타임과 같은
EditorSpecAssembler 를 써서 문서가 말하는 스펙과 편집기가 읽는 스펙이
갈라질 경로를 두지 않았다. 스펙을 두지 않은 확장에도 문서를 둔다 — 미보유가
정상일 수 있고, 그 정상 여부를 적을 자리가 없으면 다음 사람이 부재를 누락으로
오해하거나 필요한 시점을 놓친다.
초안이 낸 수치 다섯 건이 틀렸고 전부 오류 없이 "사실" 로 실릴 값이었다.
블록 최상위 키를 세어 팔레트가 79 대신 3 이 되던 것, `_` 접두 일괄 배제가
실제 항목을 삼키던 것 등을 정정했다.
게이트를 인위적으로 깨뜨려 점검한 결과 사각 하나가 드러났다 — 채워 넣으라는
표시만 지우고 서술을 쓰지 않으면 검사를 통과해, 빈 문서가 완비로 집계됐다.
미채움을 두 축으로 만들어 닫았고 되돌림으로 검산했다. 편집기 스펙 편집 시
규정이 주입되지 않던 것과 스캐폴딩 안내가 새 문서를 빠뜨리던 것도 함께 고쳤다.
이슈 본연: API 레퍼런스의 미채움 마커 5종(실측 제외/TODO/필드 없음/대표 에러 없음)
1,194건을 코드에서 읽어 전수 채우고(0건), api:docgen 재생성이 사람이 채운 내용을
손실·열화시키던 멱등성 결함 4종(CRLF, 표 파이프 이스케이프, 에러 서술 보존, 중복
라우트명 키)을 근본 수정. --check 를 실측 제외와 드리프트가 구분되도록 재정의.
ParameterDescriber/ResourceFieldDescriber 에 leaf 폴백·SEO 스코프·공통 사전 확장.
파생 결함(문서 실측 중 발견): ResponseHelper 기본 메시지 키 6종이 존재하지 않는
messages.* 를 가리켜 응답 message 가 번역문 대신 키 문자열로 노출되던 문제를 common.*
으로 정정하고, 코어 7 + gdpr/marketing/pay_kginicis/verification/ecommerce 확장의
호출부와 누락 lang 키(게시판 10키 + 이커머스 category_images 4키 포함)를 ko/en/ja
전수 정정. 중복 그룹 키 2건은 기존 키로 호출부 통합.
보안: GET /api/identity/challenges/{id} 는 권한 가드 없는 공개 폴링 엔드포인트인데
Service::getStatus 가 attempts/max_attempts 를 응답에 담아 남은 시도 횟수를 추론할 수
있었다. 두 필드를 제거하고, 챌린지 화면(admin_basic/basic)의 서버 attempts 참조를
제거(남은 횟수 UI 는 query fallback + verify 실패 시 로컬 증가로 유지).
부수 정리(변경셋에 들어온 board 컨트롤러의 audit 사전 결함): FormRequest 4개 신설로
base Request 주입 제거, CommentController 의 Board 직접 호출을 BoardService 위임으로
전환, PHPDoc @return 보강. board 스위트에서 발견한 stale test 3건(seed SSoT 불일치,
admin 계정 user 역할 누락)도 같은 세션에서 정정.
버전 정렬(공개 release 기준): 코어 7.0.3→7.0.4, sirsoft-board 1.0.1→1.0.2,
verification_kginicis 1.0.0→1.0.1, admin_basic 1.0.1→1.0.4.
재생성이 사람이 채운 서술과 이전 실측 결과를 지우고, 코드가 바뀌지 않은
문서까지 매 실행마다 흔들던 결함 5건을 고쳤다.
- 중첩 객체 파라미터가 문서에서 통째로 누락되던 문제: 배열 요소(items.*.id)를
상위로 대표시키려던 스킵 조건이 점(.) 포함 여부만 봐서, 와일드카드가 없는
중첩 객체 필드(refund_bank.*, general.*, content.* 등 17개 엔드포인트 수백 개)
까지 함께 버렸다. 와일드카드가 있을 때만 스킵하도록 좁혔다.
- 사람이 보강한 에러 응답 표가 자동 추론 초안에 덮여 사라지던 문제:
상태코드 키 단위로 병합한다.
- 실측 실패가 이전에 관측해 둔 응답 예시를 지우던 문제: 실측 성패는 호출 시점
데이터 유무에 좌우되므로(DELETE /checkout 은 대상이 없으면 404), 실패는
"새로 관측하지 못했다"는 뜻이지 기존 관측이 무효라는 뜻이 아니다.
- 실측 예시값·응답 예시 JSON 이 DB 상태를 그대로 반영해 비멱등하던 문제:
값이 아니라 스펙(필드 집합·타입)이 바뀐 경우에만 갱신한다. nullable 이
null 로 관측된 것은 타입 변경이 아니므로 기존 값을 유지한다.
- 요청 예시 path 파라미터가 실측 성패에 따라 흔들리던 문제: placeholder 로 고정.
결과: 문서 63개 전수 대조에서 손실 0(서술·표 셀·응답 예시), 전 scope 연속
재생성 시 diff 0(멱등).
토스페이먼츠 플러그인을 프로덕션 수준으로 완성한다 (계획서 S4).
주문서형 결제(9종 동적등록)
- 플러그인이 filter_available_payment_methods 로 결제수단을 주입하면 체크아웃에
독립 항목으로 노출된다. 서버 전송 시에는 core_payment_method 로 번역해 보낸다 —
코어 PaymentMethodEnum 은 toss_* 를 거부하므로 번역 없이는 주문 자체가 422 로 실패했다.
번역 근거인 core_payment_method 가 설정 병합/스냅샷의 화이트리스트에서 탈락하던 것을
provider-agnostic 하게 보존하도록 고쳤다 (토스 전용 분기 없음).
가상계좌·웹훅·에스크로
- 입금통보/결제상태 웹훅 2종 신설. secret 대조(hash_equals)·리플레이 멱등·CSRF 면제.
- 에스크로 3상태(off/on/buyer_choice). escrowProducts 를 가상계좌·계좌이체 양쪽
SDK 페이로드에 싣는다 — 서버가 조립해도 SDK 로 전달되지 않으면 토스가 결제를 거부한다.
E2E 가 SDK 경계를 직접 캡처해 이 계약의 나머지 절반을 잠근다.
- 관리자 설정 저장 시 입금기한·에스크로 값 범위를 서버에서 검증한다 (UI max 는 클라 힌트라
API 직접 호출을 막지 못한다).
레이아웃 리스너 실행 순서
- KG 는 no-PG 리스트를 통짜 리터럴로 str_replace 하므로 토스가 먼저 append 하면 KG 의
매치가 깨진다. HookManager 는 ksort 오름차순이므로 토스 priority 를 30 으로 두어
"KG(20) 먼저" 를 플러그인 로드 순서와 무관한 불변식으로 고정했다.
코어 — API 문서 생성기가 확장 web 라우트도 수집
- PG 콜백·웹훅은 CSRF/세션 특성상 web.php 에 등록되지만 외부 시스템이 호출하는
machine-facing 엔드포인트라 API 레퍼런스 대상이다. api/ prefix 만 수집하던 탓에
영구 무문서였다. 확장 소유 web 라우트를 수집하되 관리자 화면(admin 컨텍스트)은 제외한다.
코어 라우트 수집 결과는 291건으로 불변.
하네스 — 확장 테스트 베이스클래스 룰 신설
- coverage.json 의 test-extension-base-class 가 status:todo(룰 미구현)라 규정이 있어도
검출되지 않았고, 실제로 이번 신설 테스트가 그 사각에 빠졌다. 룰을 구현해 봉인한다.