기타개발지식/풀스택개발

[npm][보안] org member removal incident 뒤 package approve freeze timing을 어떤 owner-2FA 점검표로 같이 남기나

Sophie_ 2026. 8. 25. 20:19

IT 리서치 노트

[npm][보안] org member removal incident 뒤 package approve freeze timing을 어떤 owner-2FA 점검표로 같이 남기나

npm incident에서 org member removal과 package approve freeze가 같이 걸리면 많은 팀이 '2FA가 막았다'는 한 줄로 정리한다. 하지만 2026년 8월 25일 기준 npm 공식 문서를 다시 보면 bypass 2FA 토큰은 direct publish 경계까지만 일부 허용되고, maintainer·team·org governance와 staged approval은 interactive 2FA를 별도로 요구한다. 이 글은 멤버 제거 사고 뒤 package approval이 얼어붙는 시간을 어떤 owner-2FA 점검표로 같이 남겨야 하는지 정리한 것이다.

1. 개요

결론부터 말하면 org member removal incident에서는 governance 작업 시각과 package approval freeze 시각을 같은 필드에 넣으면 안 된다. owner나 maintainer가 interactive 2FA를 완료한 시각, team access revoke 시각, staged approval 재개 시각, direct publish fallback 사용 여부를 서로 다른 줄로 남겨야 나중에 책임과 복구 범위가 맞는다. 각 줄마다 권한 변경 결과를 확인하고, 설정 변경 로그를 확인하고, release 응답 시간을 확인한다고 적어 두면 incident review가 훨씬 빨라진다.

이미 bypass 2FA direct publish와 governance 경계 글이 정책 선을 설명했다면, 이번 글은 그 경계가 실제 incident memo에서 어떤 필드로 갈라져야 하는지에 대한 후속편이다. 또 reviewer 2FA 흔적과 stage ID 감사 필드 글을 같이 보면 사람 승인 증거와 패키지 승인 흐름을 더 구체적으로 설계할 수 있다.

2. 어디서 실제로 막히는가

실무에서 가장 자주 생기는 문제는 두 가지다. 첫째, 누군가를 조직이나 패키지 권한에서 빼는 governance 작업과, 이미 stage된 패키지를 approve하거나 hold 해제하는 release 작업이 한 incident 메모에 뒤섞인다. 둘째, bypass 2FA 토큰으로 publish는 된 경험이 있어서 maintainer 제거, team access 변경, token 관리까지 같은 자동화 경로로 처리할 수 있다고 착각한다. 그래서 운영자는 권한 변경 로그를 확인하지 않고, 릴리스 담당자는 approve 응답만 확인한 채 incident를 닫아 버리기 쉽다.

하지만 npm의 access token 문서는 2026년 8월 기준 bypass 2FA 토큰이 account-identity와 governance 작업을 처리할 수 없다고 분명히 적고 있다. package publishing 2FA 문서는 package settings에서 token 허용 여부를 따로 관리할 수 있다고 설명하고, staged publishing 문서는 approve 단계가 bypass 2FA 토큰으로 우회되지 않는다고 적는다. 즉 조직 정리와 package approval은 이름만 비슷할 뿐 다른 통제면이다.

여기서 사고 메모가 흐트러지는 이유는 작업 순서 때문이다. 보안 담당자는 owner 2FA를 마치고 org member removal을 끝냈다고 생각하지만, 릴리스 담당자는 package approval freeze가 아직 풀리지 않았을 수 있다. 반대로 release 쪽은 approve를 재개했는데 팀 access나 maintainer 권한이 아직 살아 있는 경우도 있다. 이 둘을 시간 축에서 떼어 두지 않으면 incident review에서 누가 무엇을 끝냈는지 설명이 어렵다.

  • 증상: 멤버 제거는 끝났는데 package publish가 계속 hold 상태다.
  • 실패: owner 2FA 완료와 approve freeze 해제 시각을 한 줄에 적는다.
  • 막힘: maintainer 제거, team revoke, stage approve 재개를 같은 담당자 작업으로 본다.
  • 누락: direct publish fallback이 실제로 사용됐는지, staged path가 유지됐는지 기록하지 않는다.
증상 먼저 볼 곳 판단 기준
member removal은 끝났는데 패키지 승인만 멈춤 approve_freeze_started_at / resumed_at staged approval 경로가 별도로 막혔는지 본다
publish는 되지만 governance 작업은 실패 token 종류와 interactive 2FA 여부 bypass token이 아닌 사람 2FA가 필요한지 본다
incident review에서 담당자 책임이 불명확 owner_2fa_completed_at / team_access_revoked_at governance 작업과 release 작업을 분리 기록했는지 본다

3. 실무에서 적용하는 순서

가장 실용적인 대응 순서는 다섯 단계다. 먼저 누가 owner 2FA를 완료했는지 기록한다. 다음으로 maintainer 제거와 team package access revoke를 끝낸다. 세 번째로 package publish가 direct path인지 staged path인지 확정한다. 네 번째로 staged approve freeze가 걸린 시각과 해제 시각을 따로 남긴다. 마지막으로 package page visible 시각이나 dist-tag 복구 시각처럼 release 복구 신호를 governance 메모와 분리해 적는다. 이때 콘솔에서 권한 설정을 확인하고, CLI 응답을 확인하고, package page 결과를 확인하는 세 줄을 같이 남기면 나중에 로그 비교가 쉬워진다.

  1. owner 2FA 완료 시각을 먼저 남긴다.
  2. org member removal과 team access revoke를 별도 항목으로 처리한다.
  3. publish path가 staged approve인지 direct publish fallback인지 확인한다.
  4. approve freeze 시작/해제 시각을 별도로 기록한다.
  5. release 복구 신호와 governance 완료 신호를 따로 보고한다.

이 순서를 쓰면 release manager와 security owner가 같은 incident를 보더라도 서로 다른 질문을 빠르게 자를 수 있다. security owner는 '권한이 실제로 회수됐는가'를 보고, release manager는 '사람 승인 흐름이 언제 다시 열렸는가'를 본다. direct publish fallback을 임시로 썼다면 그 시각과 사용 범위도 따로 남겨야 package approval freeze 메모와 섞이지 않는다. 특히 npm 명령 결과, 콘솔 설정 화면, package page 응답 결과를 각각 확인한다고 적어 두면 누가 무엇을 실행했는지 다시 조회하기 쉽다.

incident 메모 예시
owner_2fa_completed_at=2026-08-25 09:12 KST
maintainer_removed_at=2026-08-25 09:18 KST
team_access_revoked_at=2026-08-25 09:20 KST
publish_path=staged_approval
approve_freeze_started_at=2026-08-25 09:15 KST
approve_resumed_at=2026-08-25 09:41 KST
package_page_visible_at=2026-08-25 09:46 KST

이런 형식이면 나중에 '토큰은 살아 있었는데 왜 publish는 막혔는가' 같은 질문에도 답하기 쉽다. publish는 bypass token이나 trusted publishing으로 계속 움직일 수 있었더라도, staged approve나 owner-level governance는 사람 2FA를 별도로 요구할 수 있기 때문이다.

4. 공식 문서와 예시 화면으로 확인하기

첫 화면은 npm의 access token 문서다. 2026년 8월 기준 bypass 2FA 토큰이 모든 작업을 대신하는 경로가 아니라, account-identity와 governance 작업은 interactive 2FA가 필요하다는 선을 먼저 확인해야 한다.

npm 문서는 bypass 2FA 토큰으로도 account-identity와 governance 작업은 처리할 수 없고 interactive 2FA가 필요하다고 설명한다.
npm 문서는 bypass 2FA 토큰으로도 account-identity와 governance 작업은 처리할 수 없고 interactive 2FA가 필요하다고 설명한다.

즉 멤버 제거 사고가 났다고 해서 publish 토큰 하나로 maintainer 정리와 조직 권한 회수까지 끝낼 수는 없다. publish 경로와 owner·team 정리 경로를 서로 다른 타임라인으로 기록해야 하는 이유가 여기서 생긴다.

두 번째 자료는 package settings의 publishing access 문서다. package별로 token 허용 여부를 다르게 둘 수 있기 때문에, org member removal과 package approve freeze는 같은 변경 메모로 뭉개면 안 된다.

package별 publishing access 설정은 token 허용과 interactive 2FA 강제를 나눠 두며, incident 시 어떤 package가 freeze됐는지 따로 적어야 한다.
package별 publishing access 설정은 token 허용과 interactive 2FA 강제를 나눠 두며, incident 시 어떤 package가 freeze됐는지 따로 적어야 한다.

여기서 중요한 것은 '계정 2FA 상태'와 '패키지 publish gate'가 같은 스위치가 아니라는 점이다. 사고 후에는 owner 정리, package freeze, staged approval 복구가 서로 다른 체크 항목이 된다.

세 번째 화면은 staged publishing 문서다. stage 자체와 approve 단계가 분리되고, approve는 bypass 2FA 토큰으로 우회되지 않는다는 점을 사고 메모에 남겨야 release freeze 시각이 맞는다.

staged package approval은 bypass 2FA 토큰으로 우회되지 않으므로 approve freeze와 owner 정리는 다른 축으로 관리해야 한다.
staged package approval은 bypass 2FA 토큰으로 우회되지 않으므로 approve freeze와 owner 정리는 다른 축으로 관리해야 한다.

실제 운영에서는 publish job이 정상인데 approval이 막히는 시간이 발생할 수 있다. 이때 org member removal을 먼저 끝냈는지, package approve freeze가 언제 해제됐는지를 같은 타임라인에 분리해서 남기는 편이 재발 방지에 유리하다.

사고 대응에서 가장 먼저 필요한 것은 작업 종류를 자르는 표다. owner·maintainer 회수, team access 변경, staged approval, direct publish 복구를 같은 줄에 쓰면 누가 2FA를 언제 완료했는지 금방 흐트러진다.

org member removal incident에서 governance 작업과 publish approval 작업을 나눠 기록하는 표다.
org member removal incident에서 governance 작업과 publish approval 작업을 나눠 기록하는 표다.

이미 bypass 2FA direct publish와 governance 경계 글을 봤다면, 이번 표는 그 경계를 실제 incident 기록으로 옮기는 단계다.

마지막 자료는 owner 2FA와 package approve freeze를 같이 남길 때 필요한 점검표다. 이 메모가 없으면 멤버 제거는 끝났는데 staged approval만 남았는지, 아니면 반대로 approval은 끝났는데 team access가 살아 있는지 금방 섞인다.

owner 2FA 완료 시각과 package approve freeze 구간을 같이 남기는 incident 체크리스트다.
owner 2FA 완료 시각과 package approve freeze 구간을 같이 남기는 incident 체크리스트다.

특히 approve actor와 reviewer 2FA timeline 글과 같이 보면 사람이 승인한 시점과 package visibility 복구 시점을 더 촘촘하게 이어 붙일 수 있다.

5. 주의사항과 리스크

첫 번째 리스크는 bypass 2FA direct publish 경험을 account governance까지 확대 해석하는 것이다. 두 번째 리스크는 owner 2FA 완료를 package release 복구와 같은 신호로 보는 것이다. 세 번째 리스크는 멤버 제거 사고 중 direct publish fallback을 쓰고도 그 사실을 stage approval 메모에 남기지 않아 나중에 release path가 달라진 사실을 놓치는 것이다.

incident가 끝나면 최소한 네 가지를 다시 확인하는 편이 좋다. owner 2FA 완료 여부, team access revoke 완료 여부, package approval 재개 여부, package page 반영 여부다. 이 네 개는 모두 '완료'처럼 보이지만 성격이 다르다. 하나가 끝났다고 나머지가 끝난 것은 아니다.

  • owner 2FA와 package approval은 같은 완료 신호가 아니다.
  • governance revoke 시각과 release resume 시각을 반드시 분리한다.
  • direct publish fallback을 썼다면 staged path와 별도로 기록한다.

6. 결론

org member removal incident 뒤 package approval이 함께 흔들릴 때 필요한 것은 더 강한 한 줄 경고가 아니라 더 잘 분리된 시간표다. owner 2FA, member revoke, team revoke, approve freeze, release visibility를 따로 남겨야 사고 검토와 재발 방지가 쉬워진다.

  • owner 2FA 완료 시각을 별도 필드로 남긴다.
  • team access revoke와 approve freeze를 다른 줄로 적는다.
  • release 복구 신호는 governance 완료와 분리해 보고한다.

7. 참고 링크

  1. https://docs.npmjs.com/about-access-tokens/
  2. https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/
  3. https://docs.npmjs.com/managing-team-access-to-organization-packages/
  4. https://docs.npmjs.com/cli/v12/commands/npm-stage/
  5. https://docs.npmjs.com/cli/v8/commands/npm-owner/