보안이슈

ash_graphql 취약점 6건 분석|공격 조건과 대응

ash_graphql 1.11.0에서 수정된 CVE 6건을 쿼리 복잡도, Relay 입력, 구독 권한, 오류 경로로 나눠 영향 조건과 업데이트 후 검증 순서를 설명합니다.

ash_graphql 취약점 6건과 쿼리·구독·오류 경계를 정리한 표지
ash_graphql 취약점 6건과 쿼리·구독·오류 경계를 정리한 표지

ash_graphql은 Elixir의 Ash 애플리케이션에서 GraphQL API를 구성하는 라이브러리입니다. 2026년 8월 30일 공개된 1.11.0 릴리스에는 서로 다른 실행 경계를 건드리는 보안 수정 여섯 건이 함께 들어갔습니다. 단순히 같은 패키지에서 CVE가 여러 개 나왔다는 의미보다, 쿼리 분석·Relay 노드 조회·구독 알림·오류 응답이라는 GraphQL 처리 단계마다 별도의 검토가 필요하다는 점이 중요합니다.

영향 범위는 CVE마다 다릅니다. 쿼리 복잡도 우회는 0.16.23 이상 1.11.0 미만, Relay 노드 입력 처리는 0.27.0 이상 1.11.0 미만, 오류 경로 노출은 1.9.0 이상 1.11.0 미만이 대상입니다. 구독 관련 세 건도 1.11.0에서 수정됐지만 실제 위험은 애플리케이션이 구독 기능, 다중 테넌트 자원, 배치 처리 또는 재진입 발행을 어떻게 사용하는지에 따라 달라집니다. 따라서 패키지 버전 하나만 보는 대신 GraphQL 스키마와 구독 구성을 함께 확인해야 합니다.

여섯 취약점의 위치

CVE-2026-81636은 Relay 또는 keyset 페이지네이션의 first·last 인수를 쿼리 복잡도 계산이 충분히 반영하지 못하는 문제입니다. 복잡도 제한을 켜 둔 서비스라도 중첩된 연결을 큰 페이지 크기로 요청하면, 분석기가 낮은 점수를 계산하는 동안 실제 데이터베이스 작업량은 크게 늘어날 수 있습니다. 공식 권고는 인증되지 않은 클라이언트도 스키마가 허용하는 범위에서 이 조건을 만들 수 있으며, 결과가 자원 고갈과 서비스 거부로 이어질 수 있다고 설명합니다.

CVE-2026-81633은 Relay의 node(id:) 입력 처리에서 알 수 없은 노드 유형을 받았을 때 예외가 발생하는 문제입니다. 1.11.0은 이 상황을 서버 프로세스를 깨뜨리는 예외가 아니라 GraphQL 오류 응답으로 처리하도록 바꿨습니다. 쿼리 복잡도 문제와 마찬가지로 외부 GraphQL 엔드포인트가 직접 입력을 받는다는 점에서, API 게이트웨이의 일반적인 요청 수 제한만으로는 라이브러리 내부 오류 처리를 대신할 수 없습니다.

ash_graphql의 쿼리 처리·구독 경계·오류 처리 취약 지점 6곳
쿼리·구독·오류 처리의 서로 다른 영향 지점

CVE-2026-80223은 다중 테넌트 구독에서 가장 직접적인 데이터 경계 문제입니다. 구독 resolver가 알림 payload를 메모리에서 권한 검사하면서 테넌트 범위의 읽기를 다시 수행하지 않아, 한 테넌트의 구독자가 다른 테넌트 레코드를 받을 수 있은 조건이 생겼습니다. 공식 권고가 제시한 공격 조건에는 구독 기능, 다중 테넌트 자원, 필터 평가만으로 통과하는 정책, 인증된 구독자가 포함됩니다. 일반 조회 권한이 올바르더라도 실시간 알림 경로는 별도 경계로 봐야 합니다.

CVE-2026-81643은 배치로 묶인 구독 알림 전체에 권한 필터가 적용되지 않던 문제입니다. 배치의 첫 항목만 검사하는 흐름 때문에 같은 묶음의 뒤쪽 레코드가 구독자의 권한 범위를 벗어날 수 있었습니다. 1.11.0은 배치 전체를 대상으로 구독 권한 필터를 적용합니다. CVE-2026-80223이 테넌트 범위의 읽기 경계를 강조한다면, 이 취약점은 한 번에 여러 알림을 처리할 때 모든 항목을 같은 기준으로 검증해야 한다는 점을 보여 줍니다.

CVE-2026-82367은 동기식 재진입 발행에서 서로 다른 구독의 해결 결과가 섞일 수 있은 문제입니다. 기존 처리에서 사용하던 프로세스 키가 재진입 상황을 충분히 구분하지 못해, 한 토픽에서 계산한 결과가 다른 토픽의 처리와 혼선될 수 있었습니다. 수정판은 해결 결과를 보관하는 프로세스 키를 격리해 이 경계를 분리합니다. 구독 이벤트가 다시 다른 발행을 촉발하는 설계라면 단순 수신 테스트가 아니라 연쇄 발행 시나리오까지 회귀 시험에 포함하는 편이 안전합니다.

CVE-2026-78693은 애플리케이션의 오류 handler가 경로 정보를 지웠는데도 ash_graphql이 원래 오류 경로를 다시 붙이던 문제입니다. 그 결과 외부에 노출하지 않으려던 내부 필드 이름이 GraphQL 오류 응답에 포함될 수 있었습니다. 1.11.0은 handler가 반환한 결과를 존중하도록 처리 순서를 바로잡았습니다. 오류 메시지만 치환하고 path 필드를 따로 확인하지 않았던 서비스라면, 수정 후 실제 실패 요청에서 내부 필드명이 빠지는지 검증해야 합니다.

영향 판단 기준

먼저 배포된 애플리케이션이 ash_graphql을 직접 의존하는지, 다른 라이브러리를 통해 간접 의존하는지 확인합니다. lock 파일과 빌드 산출물의 실제 해석 버전을 함께 봐야 합니다. 개발 환경의 manifest만 갱신하고 운영 이미지가 이전 lock 상태를 포함하면 조치가 끝난 것이 아닙니다. 여러 서비스가 공통 이미지를 사용한다면 이미지 digest와 각 환경의 배포 시각도 대응 범위에 포함합니다.

  • Relay 또는 keyset 페이지네이션을 외부 쿼리에 제공하고 복잡도 제한을 주된 보호 장치로 사용하는 서비스
  • GraphQL 구독을 활성화하고 다중 테넌트 자원이나 배치 알림을 처리하는 서비스
  • 구독 이벤트 안에서 다른 이벤트를 동기적으로 다시 발행하는 처리 흐름
  • 사용자 정의 error_handler로 내부 필드와 경로를 가리는 서비스
  • node(id:) 조회를 외부 클라이언트에 제공하는 Relay 스키마

각 조건이 없으면 해당 취약점의 직접적인 경로는 줄어듭니다. 하지만 여섯 건이 같은 수정판에 묶여 있으므로 특정 기능을 쓰지 않는다는 이유로 이전 버전을 유지하기보다, 공식 수정판을 기준으로 의존성과 회귀 시험을 정리하는 편이 일관됩니다. 특히 다중 테넌트 서비스는 일반 쿼리와 구독에서 권한 모델이 같다고 가정하지 말고 두 경로를 분리해 확인해야 합니다.

업데이트와 검증 순서

공식 수정판은 ash_graphql 1.11.0입니다. 패키지 제약을 바꾼 뒤 의존성 해석 결과와 lock 파일을 검토하고, 새 빌드 산출물이 실제 운영 환경에 배포됐는지 확인합니다. 급한 차단을 위해 GraphQL 엔드포인트의 요청 크기와 실행 시간을 제한할 수 있지만, 이는 라이브러리의 복잡도 계산·권한 검사·오류 처리 결함을 수정하지 않습니다. 네트워크 제한은 업데이트 전 임시 방어로 두고 공식 수정판 적용을 최종 조치로 삼아야 합니다.

ash_graphql 의존성 확인부터 회귀 테스트까지의 대응 순서
의존성 확인·수정판 적용·GraphQL 회귀 시험
  1. 운영 서비스의 lock 파일과 컨테이너 또는 릴리스 산출물에서 ash_graphql 해석 버전을 확인합니다.
  2. 프로젝트가 허용하는 의존성 범위 안에서 공식 수정판을 적용하고 산출물을 새로 빌드합니다.
  3. 중첩된 Relay 페이지네이션 요청이 복잡도 제한과 페이지 상한에 맞게 거부되거나 제한되는지 시험합니다.
  4. 테넌트가 다른 구독자와 레코드를 준비해 단일·배치 알림 모두에서 교차 전달이 차단되는지 확인합니다.
  5. 재진입 발행 시 토픽별 결과가 섞이지 않는지, 알 수 없은 Relay 노드가 정상적인 GraphQL 오류로 반환되는지 점검합니다.
  6. 오류 handler가 제거한 내부 경로가 응답에 다시 나타나지 않는지 확인한 뒤 운영 로그와 경보 기준을 갱신합니다.

회귀 시험은 취약점 재현용 payload를 만드는 방식보다 서비스가 기대하는 보안 속성을 확인하는 방식으로 구성하는 것이 좋습니다. 큰 페이지 인수는 설정한 복잡도 한계에서 제어되고, 다른 테넌트의 레코드는 단일 알림과 배치 알림 모두에서 전달되지 않으며, 오류 handler가 숨긴 필드는 응답에 나타나지 않아야 합니다. 이 세 기준은 공격 세부 구현을 재현하지 않아도 수정 효과를 검증할 수 있습니다.

운영 점검 포인트

업데이트 직후에는 GraphQL 오류율, 요청 지연, 데이터베이스 읽기량, 구독 전달 실패율을 함께 관찰합니다. 복잡도 계산이 더 엄격해지면 기존에 허용되던 큰 Relay 요청이 거부될 수 있고, 구독 권한 필터가 전체 배치에 적용되면서 숨겨져 있던 정책 설정 문제가 드러날 수 있습니다. 이런 변화는 수정판을 되돌릴 이유가 아니라 스키마의 페이지 상한과 권한 정책을 명확하게 다듬을 신호입니다.

다중 테넌트 회귀 시험에는 최소 두 테넌트의 구독 세션, 단일 알림, 여러 알림이 한 번에 들어오는 배치, 이벤트가 다른 발행을 유발하는 재진입 흐름을 포함합니다. 응답 본문뿐 아니라 구독 전송 계층과 서버 로그에서도 테넌트 식별자가 섞이지 않는지 다룹니다. 오류 응답은 메시지와 path를 함께 검토해 외부 GraphQL 이름과 내부 Ash 필드가 의도대로 구분되는지 확인합니다.

이번 수정 묶음의 공통점은 입력 한 번을 처리하는 단일 함수보다 경계 사이의 연결에서 문제가 생겼다는 데 있습니다. 쿼리 분석 결과와 실제 실행량, 구독자의 테넌트와 알림 레코드, 배치의 첫 항목과 나머지 항목, 오류 handler의 결과와 최종 응답 사이가 모두 점검 대상입니다. 공식 수정판 적용과 함께 이 연결부를 시험해야 업데이트가 실제 서비스의 권한·가용성 목표로 이어집니다.

확인한 출처

  1. Query-complexity bypass via first/last pagination argumentsash-project · 공식 자료
  2. Cross-tenant information disclosure in the subscription resolverash-project · 공식 자료
  3. ash_graphql v1.11.0ash-project · 공식 자료

사실관계와 수치는 연결된 자료에서 다시 확인할 수 있습니다.

독자 의견

의견을 남겨주세요

0

아직 등록된 댓글이 없습니다.

개인정보·광고·외부 연락처는 입력하지 마세요.