🇰🇷 한글 설명
Twenty CRM 1.18.0 이하에서 IPv4-mapped IPv6 주소를 이용한 SSRF 보호 우회 취약점입니다. Node.js URL 파서가 IPv4-mapped IPv6 주소를 정규화(::ffff:169.254.169.254 → ::ffff:a9fe:a9fe)하지만 보호 메커니즘이 점진법 표기만 인식하여 16진수 형식은 통과하고, 인증된 사용자가 클라우드 메타데이터 엔드포인트 등 내부 IP에 접근하여 IAM 키 등 민감정보를 탈취할 수 있습니다.
💡 쉬운 설명
Twenty CRM의 보안 시스템이 특정 형식의 IPv6 주소를 인식하지 못해 우회될 수 있습니다. 로그인한 사용자가 이를 이용해 클라우드 자격증명 같은 내부 정보에 불정상적으로 접근할 수 있습니다.
🇺🇸 원문 (English)
Twenty is an open source CRM built with NestJS (Node.js). In versions 1.18.0 and earlier, the SSRF protection in twenty-server's SecureHttpClientService can be bypassed using IPv4-mapped IPv6 addresses in URL IP literals. Node.js's URL parser normalizes IPv4-mapped IPv6 addresses to compressed hex form (e.g., ::ffff:169.254.169.254 becomes ::ffff:a9fe:a9fe), but the isPrivateIp utility only recognizes the dotted-decimal notation. As a result, the hex form passes the SSRF check unchecked. Additionally, the socket lookup validation event does not fire for IP literal addresses, bypassing the second validation layer. An authenticated user can reach any internal IP, including cloud metadata endpoints, to exfiltrate credentials such as IAM keys.
📍 영향받는 시스템
Twenty CRM 1.18.0 이하 (NestJS 기반)
⚔️ 공격 벡터
인증된 사용자가 IPv4-mapped IPv6 주소 형식(::ffff:a9fe:a9fe)의 HTTP 요청을 통해 내부 IP 접근
🛡️ 대응 방법
Twenty CRM을 1.18.1 이상으로 업그레이드하거나 isPrivateIp 검증 로직을 IPv6 주소 형식까지 확대 수정
🔧 검증 코드
Twenty 패키지 버전이 1.18.0 이하면 취약하고 1.18.1 이상이면 패치되었으므로 패키지.json 또는 node_modules의 버전 번호를 확인하여 업그레이드 필요 여부 판단
npm list 2>/dev/null | grep -i twenty || cat package.json 2>/dev/null | grep 'twenty'