Zenn 사용자 tomi, Zero Wire RSS로 공개 서버 취약점 점검 자동화
Zenn 사용자 tomi는 Zero Wire 브리핑의 CVE를 자신의 공개 서버 인벤토리와 매일 대조하는 GitHub Actions 사례를 공개했습니다. Node.js·Ubuntu의 수정 버전 비교는 공식 자료와 코드가 맡고, Claude는 브리핑의 영향 조건과 자산 정보를 바탕으로 결과를 정리하며 미수정 취약점은 GitHub Issue로 알립니다.

Cloudflare는 2026년 11월 3일 Cloudflare Radar에 Zero Wire를 공개했습니다. 전체 CVE를 망라하는 목록이 아니라 인터넷에 노출된 웹 애플리케이션, 런타임, 라이브러리와 서비스의 중대한 취약점을 선별해 브리핑으로 제공합니다. 브리핑에는 잠재적 영향과 조사 대상, 권고 대응, 기술 근거와 공급사 지침이 담깁니다. Zenn 사용자 tomi는 11월 7일 이 RSS를 자신의 공개 서버 점검에 연결한 운영 사례를 공개했습니다.
이 구성에서는 GitHub Actions가 매일 실행되면 러너가 SSH로 서버에 접속해 인벤토리 수집 스크립트를 실행합니다. 스크립트는 서버에 별도 프로그램을 설치하지 않고 읽기 전용으로 OS와 커널, PHP·nginx·OpenSSL·Node.js 같은 런타임, 열린 포트, 설치 패키지와 미적용 업데이트, Docker 컨테이너를 수집합니다. 설정 변경이나 재시작은 하지 않습니다. 프로세스 인자와 환경변수는 비밀번호가 들어갈 수 있어 기본 수집 대상에서 제외하지만, Next.js 서버는 프로세스 인자에 표시된 버전 정보를 기록합니다. Actions 러너가 접속할 때는 서버의 공개 호스트 키를 known_hosts와 대조합니다.
수집 과정에서는 nvm으로 설치한 Node.js가 비대화형 SSH 세션의 PATH에 잡히지 않는 문제가 있었습니다. node -v만 실행하면 버전을 놓칠 수 있어, tomi는 실행 중인 프로세스의 /proc/<pid>/exe와 nvm 설치 경로 등을 확인해 Node.js 버전을 찾도록 했습니다.
취약점 비교 단계는 Zero Wire RSS에서 CVE 번호를 뽑아 공식 취약점 자료와 대조합니다. 처음에는 이 버전 비교까지 Claude에 맡겼지만, 수정 버전을 찾지 못해 결과가 ‘요확인’으로 남는 경우가 있었습니다. 이후 Node.js 취약 범위와 수정 범위는 Node.js 보안팀의 JSON 자료에서 읽고 semver로 비교하도록 바꿨습니다. Ubuntu 패키지는 Ubuntu Security의 CVE 자료에 있는 배포판별 수정 버전을 dpkg --compare-versions로 확인합니다. Ubuntu는 상류 버전보다 오래된 번호에 수정 사항을 백포트할 수 있어, 상류 버전 번호만으로 비교하지 않습니다. 저장소의 npm 의존성은 package-lock.json을 npm audit으로 검사합니다. 기본적으로 RSS에 실린 CVE를 대조하되, Node.js 본체는 설치 버전에서 미수정으로 남은 취약점도 RSS에 실린 항목과 별도로 집계합니다.
코드가 버전 상태를 판정한 뒤 Claude는 브리핑의 영향 조건과 자산 정보를 함께 읽고, 자산별 결과를 ‘영향 있음’, ‘요확인’, ‘해당 없음’으로 정리합니다. tomi는 Claude에 Bash를 허용하지 않았습니다. SSH 수집은 앞선 단계에서 끝내고, Claude에는 파일 읽기·쓰기와 제한된 도메인의 웹 조회만 맡겼습니다. RSS와 조회한 웹페이지에 에이전트를 겨냥한 지시가 있어도 따르지 않고 자료로만 취급하도록 프롬프트를 구성했습니다.
운영 과정에서 드러난 예외는 OS 패키지와 애플리케이션 런타임이 같은 라이브러리를 사용하지 않을 수 있다는 점입니다. tomi가 든 node2shell 사례에서는 Ubuntu의 brotli 패키지가 수정된 것으로 판정됐지만, nvm으로 설치한 Node.js는 Brotli와 OpenSSL을 자체 포함해 사용합니다. 따라서 OS 패키지의 수정 상태만으로 Node.js 런타임까지 수정된 것으로 처리하지 않도록 했습니다. Ubuntu 자료에서 pending은 수정판이 준비돼 공개를 기다리는 상태이고, needs-triage는 아직 평가되지 않은 상태입니다. 이 두 상태도 구별해 영향 판단에 반영합니다.
대응이 필요한 결과는 기존 GitHub Issue가 있으면 댓글을 추가하고, 없으면 새 Issue를 만듭니다. 기계 판정에서 미수정 취약점이 나오면 Claude가 작성한 상태 표시와 관계없이 Issue를 생성합니다. 수정판 공개를 기다리는 동안 매일 작업이 실패로 표시되지 않도록 알림과 작업 상태도 분리했습니다. 결과는 Issue로 알리고 작업은 경고 상태로 남깁니다. 보고서에는 호스트명과 버전, 열린 포트가 포함될 수 있어 tomi는 저장소를 비공개로 운영하며, 점검 전용 SSH 계정에 sudo 권한을 주지 않는 방식을 권했습니다. 이 자동화는 취약점 판정과 보고까지 맡고, 서버 업데이트와 재시작은 운영자가 처리합니다.