Files
llm-wiki/raw/blog-topics/archunit-jackson-default-typing-cve-2019-14379-block-2026-05-29.md

9.1 KiB
Raw Permalink Blame History

title, source_type, status, related_branches, related_projects, tags, created, status_label, target_audience, inspiration_url, archive_url
title source_type status related_branches related_projects tags created status_label target_audience inspiration_url archive_url
blog-topic / archunit-jackson-default-typing-cve-2019-14379-block-2026-05-29 blog-topic raw
feature-boundary-validation-mapping-contract
ca-tmpl
blog-topic
ca-tmpl
archunit
jackson
security
cve
fitness-function
polymorphic-deserialization
2026-05-29 ready-for-canonical backend-engineer

blog-topic: archunit-jackson-default-typing-cve-2019-14379-block-2026-05-29

Layer: raw/blog-topics/ — 채용공고가 아닌 작업·학습·트러블슈팅에서 나온 블로그 글감 원석. canonical 정제 전 raw 후보이며, wiki/blog/ 직접 생성 근거가 아니다.

Parent / 부모

트리거 / Trigger

  • 트리거 유형: branch-work
  • 트리거 날짜: 2026-05-29
  • 트리거 연결 노트: raw/branch-notes/feature-boundary-validation-mapping-contract — 1차 enforcement 패스에서 no_jackson_laissez_faire_subtype_validator + no_jackson_enable_default_typing_call 두 ArchUnit 규칙 + DefaultTypingFixture violations-as-data 테스트로 CVE-2019-14379 의 코드 진입점을 정적으로 차단한 작업.

글감 / Topic seed

  • 한 문장 요지: Jackson polymorphic deserialization 의 RCE 게이트 (ObjectMapper.enableDefaultTyping() / activateDefaultTyping(LaissezFaireSubTypeValidator)) 는 런타임 dependency check 가 아니라 컴파일/테스트 단계의 fitness function 으로 막아야 안전하다 — 한번 머지된 뒤에는 production 트래픽으로 RCE 가 터지는 게 검출 시점이므로 너무 늦다.
  • 떠오른 계기: feature-boundary-validation-mapping-contract B5 결정의 enforcement 단계. CVE 자체의 발견 (2019) 과 Jackson 2.10 의 @Deprecated 조치 (2019-09) 가 있었음에도, 우리 코드가 호출하지 않는다 는 사실은 매 PR 마다 사람이 보장해야 하는 규약이었다. 이걸 ArchUnit fitness function 으로 commit 으로 박은 사례.
  • 예상 제목 후보:
    • CVE-2019-14379 의 호출 경로를 ArchUnit 으로 정적 봉쇄하기
    • "Jackson 을 안전하게 쓴다" 를 컨벤션이 아닌 fitness function 으로 박는 방법
    • enableDefaultTyping() 한 줄이 RCE 가 되는 이유와 정적 차단

핵심 주장 후보 / Claim candidates

  • 사실 후보:
    • CVE-2019-14379 의 RCE 경로는 ObjectMapper.enableDefaultTyping() 활성화 + ehcache 같은 gadget class 가 classpath 에 있는 조건 — 근거: NVD CVE-2019-14379 (CVSS 9.8), Jackson 보안 가이드 enableDefaultTyping@Deprecated since 2.10 표기.
    • Jackson 2.10 의 공식 대체 API 는 activateDefaultTyping(PolymorphicTypeValidator) 이며, allowlist 구현체 BasicPolymorphicTypeValidator 또는 @JsonTypeInfo(use = NAME) + @JsonSubTypes 명시가 정식 — 근거: raw/official-docs/schema-jackson-polymorphic-deserialization.md#JACK-POLY-C1..C5.
    • LaissezFaireSubTypeValidator모든 subtype 허용 의 명시적 anti-allowlist — 클래스 이름 그 자체가 "보안 검증 없음" 의 표지 — 근거: JACK-POLY-C2.
    • ca-tmpl 의 적용: src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java 에 두 규칙 추가 — no_jackson_laissez_faire_subtype_validator (클래스 참조 차단), no_jackson_enable_default_typing_call (메서드 호출 차단). 위반 fixture 는 violations/boundary/DefaultTypingFixture.java.
    • 규칙 두 개를 분리한 이유: LaissezFaireSubTypeValidator 없이 enableDefaultTyping() 만 호출해도 (ObjectMapper.DefaultTyping.NON_FINAL 등 deprecated overload) 위험. 호출 차단과 import 차단이 독립적인 진입점 이므로 둘 다 닫아야 한다.
  • 경험 후보:
    • ArchUnit DSL 의 callMethodWhere(target(name(...))) 패턴은 호출자 의도와 무관하게 메서드 이름 으로 catch. enableDefaultTyping 이라는 메서드 이름이 ObjectMapper 외부에 존재할 가능성이 거의 0 이므로 owner 필터를 생략해도 false positive 없음 — 단순 규칙이 충분.
    • violations-as-data fixture 는 DefaultTypingFixture.unsafe() 한 메서드로 두 규칙을 동시에 catch (호출 + 참조). 한 fixture 가 서로 다른 규칙 두 개를 동시에 검증 하는 케이스 — 규칙별 1:1 fixture 가 아니어도 됨.
    • app-bootstrap 의 test classpath 에 Jackson 이 없어서 컴파일 실패 → testImplementation 'org.springframework.boot:spring-boot-starter-json' 추가. fitness function 자체에 의존성을 끌어들이는 cost 가 있음을 의식해야 한다.
  • 의견 / 해석 후보:
    • 라이브러리 버전 차단 (jackson-databind ≥ 2.10) 은 supply-chain branch 의 책임이지만, 코드 사용 차단 (deprecated API 호출 금지) 은 boundary contract 의 책임. 두 가지를 같은 PR 에서 묶으면 책임 경계가 흐려진다.
    • "CVE 가 알려진 후에는 사람이 review 로 막으면 된다" 는 흔한 반론은 시간 경과에 따른 attention decay 를 무시한다. 5년 뒤 합류한 신입이 PR review 할 때 enableDefaultTyping 이 안전한지 즉시 판단하기 어렵다 — fitness function 은 지식 보존 비용 의 외부화.
    • Jackson 2.15 의 sealed type 자동 인식 같은 조용한 행동 변화 가 들어와도, 본 규칙은 호출 자체를 차단하므로 회귀 없음 — Jackson 의 mitigation 진화를 기다리는 대신 진입점 자체를 봉쇄 하는 전략의 정당화.

Outline seed

  1. CVE-2019-14379 의 한 줄 — enableDefaultTyping() + ehcache gadget 으로 RCE (CVSS 9.8).
  2. Jackson 의 공식 대응 — 2.10 @Deprecated + PolymorphicTypeValidator + BasicPolymorphicTypeValidator allowlist.
  3. 하지만 우리 코드가 호출하지 않는다 는 사실의 유지비용 — review fatigue, 시간 경과, 신입 합류.
  4. fitness function 으로의 외부화 — ArchUnit 규칙 두 개 (callMethodWhere + dependOnClassesThat) 의 의도와 분리 이유.
  5. violations-as-data 로 규칙이 실제로 catch 하는지 박기 — DefaultTypingFixture 한 메서드가 두 규칙을 동시에 검증.
  6. fitness function 의 비용 — spring-boot-starter-json 을 test classpath 에 끌어들임.
  7. 보안 책임의 경계 — 코드 사용 차단 (boundary contract) vs 버전 차단 (supply-chain) 의 분리.
  8. 정리 — CVE 차단은 지식 보존 비용 의 코드화. fitness function 이 review 의 검토 부담을 commit 으로 이전한다.

Canonical 전환 후보 / Canonical extraction candidates

  • wiki/projects/ca-tmpl/archunit-jackson-cve-block.md 후보:
    • 실제 두 규칙 + DefaultTypingFixture 의 코드 발췌.
    • testImplementation 'spring-boot-starter-json' 추가의 비용.
    • violations-as-data 1 fixture × 2 negative test 패턴.
  • wiki/concepts/fitness-function-for-known-cve.md 후보:
    • "우리 코드가 호출하지 않는다" 를 review 로 유지하는 비용 분석.
    • 코드 사용 차단 vs 버전 차단의 책임 경계.
    • 라이브러리 mitigation 진화와 진입점 차단 전략의 trade-off.
  • 필요한 추가 검증:
    • BasicPolymorphicTypeValidator 사용을 권장 하는 메시지를 ArchUnit 위반 메시지에 포함할 가치가 있는지 — false-positive 시 개발자가 즉시 대안을 알 수 있게.
    • sealed Command 타입 도입 시 본 규칙이 @JsonTypeInfo 명시 패턴과 충돌하지 않는지 (충돌 없음 가설 — 검증은 future use case 에서).

Sources / 근거 후보

미해결 / Unknown

  • 아직 확인해야 할 사실: violation message에 BasicPolymorphicTypeValidator 대안을 포함할지 여부.
  • 과장하면 안 되는 부분: ArchUnit rule은 ca-tmpl 코드의 특정 호출/참조를 차단하는 것이며, Jackson RCE 일반 위험을 모두 제거한다고 쓰지 않는다.

Decision / 처리 결정

  • 액션: promote-to-canonical
  • 이유: wiki/projects/ca-tmpl/boundary-validation-mapping.md 에 Jackson default typing CVE static block 글감으로 반영했다.
  • 다음 단계: source canonical이 verified 상태이므로 이후 blogify 대상으로 삼을 수 있다. 단 ArchUnit rule이 탐지 가능한 호출/참조 범위로 제한된다는 점을 유지한다.