06 / Articles

라이트업 작성 규격

published / 4분 읽기 /chwrld

processwriting

이 문서는 팀 내부 문서지만 공개해 둡니다. 글마다 형식이 달라지면 읽는 쪽이 매번 구조를 다시 파악해야 하고, 무엇보다 민감정보 검토를 빠뜨리기 쉬워집니다.

새 글은 src/content/articles/<lang>/<slug>.md 에 만듭니다. 한국어판과 영어판은 같은 slug 를 써야 언어 스위처가 동작합니다.

프론트매터

스키마는 src/content.config.ts 에 정의되어 있고 .strict() 입니다. 정의되지 않은 키를 쓰면 빌드가 즉시 실패합니다. 오타 난 키가 조용히 무시되는 것보다 낫습니다.

아래는 형식을 보여주기 위한 가상의 예시입니다. 값은 실제 제보가 아닙니다.

---
title: "내부 API 접두사가 게이트웨이 인증을 우회하던 문제"
description: "라우터가 공개 접두사 한 개만 특수 처리해서, 이름이 비슷한 내부 네임스페이스 전체가 인증 없이 프록시되던 문제. 패치 기준으로 재현 절차와 영향 범위를 정리했습니다."
pubDate: 2026-09-19
updatedDate: 2026-09-22
lang: ko
tags: ["web", "authorization", "code-audit"]
author: chwrld
severity: high
target: "Example Gateway 1.4.2"
cve: ["CVE-2026-00000"]
bounty: "$750"
draft: false
---

필드별 규칙:

필드필수규칙
title필수목록 카드와 <title> 에 같이 쓰입니다. 벤더명을 앞에 붙이지 말고 결함 자체를 적습니다
description필수meta description 겸 RSS 요약 겸 카드 발췌. 한 문단, 줄바꿈 없이. 1~2문장
pubDate필수2026-09-19 — 따옴표 없이 쓰면 YAML이 날짜로 파싱합니다
updatedDate선택본문을 의미 있게 고쳤을 때만. 오타 수정으로는 올리지 않습니다
lang필수ko 또는 en. 파일이 들어 있는 디렉터리와 반드시 일치해야 합니다
tags선택소문자 kebab-case. 그대로 URL이 됩니다 (/articles/tags/web/)
author선택기본값 chwrld. src/data/team.ts 의 handle 과 맞춥니다
draft선택true 면 프로덕션 목록·RSS·사이트맵에서 빠집니다. 개발 서버에서는 DRAFT 뱃지로 보입니다
severity선택critical / high / medium / low / info. 취약점 글이 아니면 생략
target선택대상 제품과 버전. 버전 없는 target 은 6개월 뒤에 아무 의미가 없습니다
cve선택배열. 실제로 발급된 번호만. 신청만 한 상태라면 적지 않습니다
bounty선택벤더 공지 표기를 그대로. 금액 추측·환산 금지
heroImage선택public/ 기준 절대 경로 (/og/cdap.png)

slug 키는 쓰지 않습니다. slug는 파일명이 유일한 출처입니다.

draft 와 _ 접두사의 차이

둘 다 글을 숨기지만 용도가 다릅니다.

  • draft: true — 빌드에는 포함되고 목록에서만 빠집니다. URL을 직접 아는 사람은 볼 수 있으므로 리뷰용 링크 공유에 씁니다.
  • 파일명을 _wip-foo.md 로 — 컬렉션에 아예 로드되지 않습니다. 스키마 검증도 통과할 필요가 없습니다. 아직 프론트매터도 안 채운 초고에 씁니다.

미공개 취약점 세부가 들어 있는 초고는 draft: true 가 아니라 _ 접두사를 쓰세요. draft는 URL을 아는 사람에게 노출됩니다.

본문 규칙

<h1> 은 레이아웃이 title 로 만듭니다. 본문은 ## 부터 시작합니다.

코드블록

언어를 반드시 명시합니다. Shiki가 하이라이팅하는 기준이고, 없으면 회색 덩어리가 됩니다.

```http
GET /internalapi/v1/namespaces/default/config HTTP/1.1
Host: gateway.example
Authorization: REDACTED
```

요청·응답은 http, 셸은 bash, 설정 파일은 yaml / json. 디컴파일 결과나 패치 diff는 diff 를 쓰면 + / - 가 색으로 구분됩니다.

긴 출력은 잘라냅니다. 스택트레이스 200줄을 그대로 붙이는 대신 관련된 프레임만 남기고 [...] 로 표시합니다. 자른 사실을 표시하지 않고 자르면 재현하는 사람이 혼란스러워집니다.

이미지

  • public/articles/<slug>/ 아래에 두고 /articles/<slug>/foo.png 로 참조합니다.
  • alt 텍스트는 필수입니다. “스크린샷” 이 아니라 그 스크린샷에서 봐야 하는 것을 적습니다.
  • 가능하면 스크린샷 대신 코드블록을 씁니다. 텍스트는 검색되고 복사되고 diff가 되지만 PNG는 안 됩니다.
  • 스크린샷이 꼭 필요하면 브라우저 창 전체가 아니라 필요한 영역만 찍습니다. 전체 창에는 다른 탭 제목, 북마크, 알림이 같이 찍힙니다.

표

표는 재현 절차가 아니라 비교에 씁니다 — 버전별 동작 차이, 파라미터별 응답 차이. 절차는 번호 목록이 낫습니다. 열은 4개를 넘기지 않습니다. 모바일에서 가로 스크롤이 생깁니다.

인용

벤더 공지나 커밋 메시지를 인용할 때는 출처를 함께 적습니다.

> 인용문.
> <cite>벤더 권고문 SA-2026-001</cite>

공개 전 체크리스트

공개 전에 글쓴이가 아닌 다른 사람이 이 목록을 확인합니다. 자기 글에서 자기 실수를 찾는 건 잘 안 됩니다.

자격증명 · 토큰

  • 실제 세션 쿠키, Bearer 토큰, API 키가 본문·코드블록·스크린샷에 없는지
  • 있던 자리는 REDACTED 또는 명백한 더미값(eyJhbG...TRUNCATED)으로 대체했는지
  • 토큰 일부만 지운 곳이 없는지 — 앞 8자만 가린 JWT는 여전히 유효한 토큰입니다
  • 테스트에 쓴 계정 비밀번호가 본문에 없는지
  • 벤더 내부 호스트명·IP가 공개되어도 무해한지 확인했는지

타인의 데이터

  • 다른 사용자의 이메일·전화번호·이름·주문번호가 응답 예시에 없는지
  • 스크린샷 모서리, 브라우저 탭 제목, 자동완성 드롭다운에 개인정보가 없는지
  • 내부 식별자(UUID, 계정 ID)가 실제 사용자에 연결되지 않는 값인지

페이로드 범위

  • PoC가 결함의 존재를 보이는 범위에서 멈추는지
  • 그대로 실행하면 타인의 계정을 탈취하거나 데이터를 파괴하는 완성된 스크립트가 아닌지
  • 자동화 도구(대량 스캐너, 계정 열거 스크립트)를 첨부하지 않았는지

공개 가능 여부

  • 벤더가 패치를 배포했는지 확인했는지
  • 벤더가 공개에 동의했는지, 또는 공개 권고문이 이미 나왔는지
  • 버그바운티 프로그램·플랫폼 약관이 공개를 제한하지 않는지
  • 같은 코드베이스에서 찾은 아직 미패치인 변형이 글에 새어 들어가지 않았는지

마지막 항목이 실제로 가장 위험합니다. 변형 분석을 하면서 찾은 두 번째 결함이 첫 번째 글의 “이 패턴은 다른 곳에도 있습니다” 문장에 그대로 담기는 경우가 있습니다. 미패치 변형은 별도 제보가 끝날 때까지 언급하지 않습니다.


자세한 공개 판단 기준은 책임 있는 공개 정책에 있습니다.