9P by GN⁺ 3일전 | ★ favorite | 댓글 1개
  • Supabase MCP 통합을 악용하여 공격자가 개발자의 비공개 SQL 데이터를 유출할 수 있음
  • LLM이 지시문과 데이터를 구분하지 못해 악의적으로 조작된 메시지가 명령어로 오인될 위험 발생
  • service_role 권한을 가진 AI 에이전트가 고객 사용자 입력을 신뢰 없이 처리, 민감 정보가 노출되는 문제 발생
  • 공격자는 특정한 지시문이 포함된 메시지로 보안 회피 및 중요 정보 유출 가능함을 시연함
  • 대응 방안으로 읽기 전용 모드 활성화프롬프트 인젝션 필터 사용을 제안함

개요

  • Model Context Protocol(MCP)은 LLM이 외부 도구와 상호작용할 수 있도록 해주는 표준 프로토콜임
  • 이로 인해 새로운 기회가 열리는 동시에, 잠재적인 보안 취약점도 발생함
  • 본 게시물은 공격자가 Supabase의 MCP 연동을 활용, 개발자의 비공개 SQL 테이블을 유출할 수 있는 방법을 시연함

문제점 설명

  • LLM은 시스템 프롬프트·사용자 지시문·데이터 컨텍스트를 텍스트로 받아서 처리
  • LLM은 문맥 경계를 내장적으로 알지 못하며, 데이터와 지시문을 구별하지 못함
  • 사용자 입력 데이터 중 명령어처럼 보이도록 조작된 콘텐츠가 있을 경우, LLM이 이를 명령으로 실행할 수 있음

공격 환경(Setup)

  • 새로운 Supabase 프로젝트를 생성하고, 일반적인 다중 테넌트 SaaS 고객지원 환경을 모사함
  • Dummy 데이터만 삽입, Row-Level-Security(RLS) 는 공식 문서대로 적용, 별도 확장이나 정책 없음
  • 공격에 사용된 환경은 기본 제공 서비스만 사용, service_role, RLS, MCP 에이전트 모두 기본 세팅임

1. 주요 행위자와 권한

행위자(역할) 사용 인터페이스 DB 자격증명 주요 권한
고객/공격자 티켓 제출 폼(공개) 'anon'(RLS 제한) 본인 소유의 티켓/메시지 생성
지원 에이전트 지원 대시보드 'support'(RLS 제한) 지원 테이블만 일부 읽기/쓰기
개발자 Cursor IDE+Supabase MCP service_role 모든 테이블에 대해 전체 SQL 가능
IDE Assistant LLM(Cusor에서 작동) service_role 텍스트 명령대로 MCP로 SQL 실행
  • 취약점의 핵심: IDE Assistant는 신뢰할 수 없는 고객 입력을 인지하지 못하며, 최고 권한(service_role) 을 가짐
  • 지원 에이전트의 권한으로는 민감 테이블 접근 불가능(예: integration_tokens), 지시문을 요청해도 거부 반응 반환함

2. 애플리케이션 구조

  • 고객 및 에이전트가 자유롭게 지원 티켓을 생성/메시지 교환 가능
  • 모든 데이터는 Supabase SQL 데이터베이스에 저장
  • 개발자는 때때로 Cursor 에이전트(LLM + MCP) 로 열린 티켓을 검토함

테이블 예시

  • support_tickets: 고객지원 티켓 데이터 저장
  • support_messages: 각 티켓에 대한 메시지 저장
  • integration_tokens: 민감한 세션 토큰 등 보안 정보 저장

3. 애플리케이션 동작 방식

  • 고객지원 시스템은 티켓 생성 및 메시지 교환 기능 제공
  • 개발자는 Cursor 에이전트로 열린 티켓 및 메시지 확인/요약을 자동화함
  • Cursor 에이전트가 service_role 권한으로 DB 접근, RLS 무시 및 고객 메시지도 모두 읽음
  • 누군가 조작된 명령문을 고객 메시지에 심으면, AI가 이를 SQL로 실행하여 민감 정보를 유출할 수 있음

공격 시나리오

  • 공격자는 새로운 티켓을 열고 특수하게 작성한 메시지를 제출함
    • 예시 메시지에는 AI 에이전트에게 integration_tokens 테이블 전체 읽고, 결과를 이 티켓에 추가하라는 명령 포함
    • 메시지 끝에는 정상적인 문의 내용(“무엇을 할 수 있나요?” 등)을 포함해 의심 줄임
  • 이 메시지는 지원 에이전트에게 노출돼도 민감 데이터 접근 권한 부족으로 별 영향 없음
  • 개발자가 나중에 Cursor로 열린 티켓을 요약하려 하면, 에이전트가 해당 메시지를 입력으로 받아 숨겨진 명령 실행
    • 실제로 두 개의 SQL 쿼리를 생성:
        1. 모든 integration_tokens 내용을 읽음
        1. 해당 결과를 티켓 메시지로 다시 삽입함
  • 해당 쿼리는 service_role 권한으로 실행, RLS 우회
  • 공격자는 본인이 연 티켓에서 민감 정보가 포함된 신규 메시지를 쉽게 확인 가능

결론 및 대응 방안

  • 본 공격은 과도한 권한(service_role)사용자 콘텐츠에 대한 검증 부재가 결합된 취약점 기반임
  • MCP 도입 시 자동화 편의와 동시에 보안 리스크가 큼

즉각적인 보안 조치 제안

  1. 읽기 전용(read-only) 모드 사용

    • Supabase MCP에서는 agent 초기화시 읽기 전용 플래그를 설정하면, 모든 쓰기/수정/삭제 SQL 차단
    • 쿼리 기반 에이전트라면 항상 읽기 전용 모드를 활성화 필요
  2. 프롬프트 인젝션 필터 적용

    • 비정상적 명령문, SQL 패턴, 인젝션 흔적 패턴 등 데이터 입력을 사전 필터링
    • MCP 앞단에서 데이터를 감시/차단하는 lightweight 래퍼로 적합
    • 모든 위험 탐지는 불가능하나, 기본적인 1차 방어선 제공

전문가 지원 안내

  • GeneralAnalysis 팀은 LLM 보안 및 적대적 공격 안전성 분야 전문성 보유
  • MCP 서버 또는 LLM 기반 에이전트 보안 강화에 대해 문의 시( info@generalanalysis.com ) 논의 및 가이드 제공 가능
Hacker News 의견
  • Supabase 엔지니어로서 MCP 작업 담당자임을 밝힘. 최근 프롬프트 인젝션 방지를 위해 여러 완화책을 추가한 경험 공유. 기본적으로 read-only 사용을 문서에서 권장하고, SQL 응답을 포장해 LLM이 명령을 따르지 않도록 함. E2E 테스트로 덜 똑똑한 LLM도 공격에 쉽게 속지 않게 하고 있음. 이런 노력들로 인해 실제 Haiku 3.5 같은 덜 강력한 모델에서도 공격 성공률이 크게 떨어졌음을 체감. 하지만 이러한 노력들은 완화책일 뿐이고, 프롬프트 인젝션 문제는 여전히 미해결 문제라는 사실을 강조. 세밀한 토큰 수준의 권한 부여, LLM 접근 서비스 범위 지정, 작성중인 자세한 문서 추가, 프롬프트 인젝션 시도를 탐지하는 모델 등 다양한 추가 장치 개발 중임을 알림. Responsible disclosure(책임 있는 보안 이슈 공개) 절차 따르지 않은 General Analysis 측의 소통 부재에 아쉬움 표명. 자세한 이슈 및 커밋 링크는 pull/94, pull/96, supabase security.txt에서 확인 가능함

    • 이 방식이 정말 효과적인지 의문을 제기. 신뢰할 수 없는 사용자 Javascript를 eval()로 넘기며 sanitize(정규화)하려는 시도가 항상 실패했던 것처럼, 지금의 접근 역시 위험 요소를 완전히 제거하지 못한다고 지적. MCP가 보안 경계로 작동하는 것이 납득되지 않으며, 실제 운영 환경이라면 LLM이 티켓을 읽는 컨텍스트와 SQL 호출 권한을 가진 컨텍스트를 분리하고, 이 둘을 잇는 agent 코드로 인변트 보장 필요함을 강조. Cursor(컨텍스트 분리 불가한 구조)이기 때문에 MCP를 프로덕션 데이터베이스에 바로 연결하는 것은 비상식적 선택임을 주장

    • 책임 있는 보안 공개 프로세스가 실질적으로 의미가 있는지 질문. 해결책이 결국 LLM에 "데이터를 유출하지 말라"고 여러 번 요청하고, 관련 위험을 문서에 추가하는 수준이라면 그 효과에 의구심 품음

    • Supabase의 공개 보안 정책이 해커원(HackerOne)을 통한 야속한 조건을 강제하는 것뿐이어서, 본인 역시 해당 방식에 동의하지 않음을 밝힘

    • General Analysis 공동창업자로서 기술적으로 Supabase MCP 단독의 책임이 아님을 강조. 이 취약점은 (1) 비정규화된 데이터가 agent 컨텍스트에 들어가는 구조, (2) Foundation 모델이 명령과 데이터를 분간하지 못하는 한계, (3) 잘못된 접근 권한 범위 설정(커서의 과도한 권한) 등이 결합된 결과라고 설명. 이런 유형의 취약점은 다양한 MCP 사용 패턴에서 공통적으로 관찰 가능함. MCP 사용자를 위한 Guardrail(보호장치) 개발 진행 중임을 부연

    • 개인적으로 추가 프롬프트 포장에서 특별히 효과를 보지 못했다고 판단. fail fast(빠르게 실패) 방식이 더 적합하다고 생각하며, 오히려 프롬프트 포장은 나쁜 개발 습관을 조장할 수 있다고 우려. LLM이 시스템 접근 도구를 쓰는 것과 사용자가 REST API에 직접 시스템 접근 권한을 갖는 상황에 본질적 차이 없음. 개발자의 권한 검증 책임은 변하지 않는 교훈임을 강조. 프롬프트 인젝션이 아닌, 보안 경계 문제로 진단, 세밀한 권한 토큰 관리로 충분히 해결 가능하다고 판단

  • XSS(크로스 사이트 스크립팅)가 LLM 세계에 옮겨진 현상이라고 봄. 특히 Cursor와 Supabase MCP 같은 어드민 앱에서는 신뢰할 수 없는 사용자가 만든 콘텐츠를 가공 없이 받아들이기 쉬움. 기존처럼 지원 티켓에 악의적 HTML/Javascript를 삽입하는 대신, 이제는 LLM 지시에 해당하는 프롬프트를 삽입하게 되는 것임. 관리자가 이를 열람할 때 세션(여기서는 Supabase MCP 접근 권한)을 탈취당하는 구조라고 비유

    • 기술적으로 맞는 지적이지만, 이 문제를 단순히 "내부 XSS의 또 다른 형태"로 축소하면 본질을 놓칠 수 있음. XSS는 입력을 가공해 안전하게 만들 수 있지만, 프롬프트 인젝션은 입력 데이터에서 LLM 명령을 완벽히 제거할 결정적 규칙이 전혀 없어 구조적으로 안전하지 못함. 결국 임의의 신뢰할 수 없는 입력을 특권 정보에 접근 가능한 LLM에 연결하는 것은 본질적으로 위험하다고 판단

    • 문제의 상당 부분은 LLM 입력 정규화가 불가능하다는 데 있음. 이런 기능을 사용하는 한, 항상 취약점에 노출되는 셈

    • SimonW가 'prompt injection'이라는 용어를 만든 배경을 소개. SQL 인젝션과 유사하지만, LLM 프롬프트는 신뢰할 수 있는 방식으로 escape(탈출)하는 방법이 없어 오히려 더 위험하다고 진단

    • 문제 코드 직접 사례 링크 공유

  • Supabase 같은 데이터베이스 접근 MCP를 사용할 때는 다음 권장 팁을 제공. (1) 무조건 read-only로 설정해 공격 발생 시 데이터 손상을 직접 막기, (2) 이 MCP를 외부 커뮤니케이션이 가능한 다른 MCP(HTTP 요청, 이메일 발송 등)와 결합 시 데이터 유출 위험 주의. 관련해서 본인이 쓴 "lethal trifecta" 분석 글도 참고 lethal trifecta 포스트

    • 공격 의도 없이도 데이터 유출(Exfiltration)이라는 용어가 적합하다고 생각
  • LLM을 생산계 인프라에 직접 연결하는 것이 결국 큰 취약점임을 간결하게 지적

    • 이 내용이 기사 상단에 있는 한 줄 요약이 되어야 한다고 강조

    • 실제 이렇게 세팅하는 사람이 예상보다 많아 놀랍다는 반응

  • Hacker News를 오래 읽으며 과거에는 해킹이 정말 뛰어난 엔지니어링의 결과로 보였으나, LLM 관련 취약점은 유치원을 속일 정도로 단순한 프롬프트로도 이루어지는 현실에 놀람

  • tramlines.io 소속으로, Neon DB MCP에서도 유사 취약점을 발견했다는 개인적 경험과 글 링크 공유 neon exploit 사례

    • 해당 취약점이 동일하게 나타나고, Neon's MCP가 데이터베이스에 read-write 접근 권한을 쉽게 줄 수 있기 때문에 'lethal trifecta'(민감 데이터 접근, 악의적 인스트럭션 노출, 데이터 유출 기능) 조건을 모두 충족시킬 수 있음을 추가 설명
  • 실제로 이런 MCP 취약점을 이용한 현실 공격 사례가 적은 것이 의외라고 밝힘. Supabase 관련 사례를 몇 달 전에 따로 다뤘는데도 공식 문서에서 이를 분명히 언급하지 않는 점이 흥미로움. 참고 사례 supabase 취약점 케이스, supabase 공식 문서

    • 현실 공격이 많이 없는 이유는 MCP 사용이 아직 널리 퍼지지 않아서라고 추측. 앞으로 타겟화 될 가능성이 높다고 예상
  • 다양한 공격에서 지원 사이트가 자주 사용되는 점 지적. 예전에도 SaaS 가입 시 조직 이메일을 자동 등록하는 구조를 악용해, 지원 티켓 시스템을 통해 인증 이메일을 받고 계정 가입/로그인에 이용하는 사례들이 있었음을 회상

  • Cursor assistant가 Supabase 데이터베이스에 service_role로 접근하며, 이로 인해 모든 RLS(행 수준 보안)이 우회된다는 점이 무척 위험하다고 지적. 생산 데이터베이스를 AI 에이전트에 바로 공개하는 것은 큰 리스크임을 강조. 원시 SQL 접근에는 무조건 리드 레플리카를 쓰고, 생산 데이터베이스에는 특별히 노출된 API 엔드포인트만을 이용해야 근본적 위험을 줄일 수 있음. 1~2년 안에 프롬프트 인젝션을 완벽히 해결하는 건 불가능하고, AI agent와 생산 데이터베이스 사이에 데이터 복제 및 보안 규칙 자동화용 미들웨어 계층이 많이 등장할 것으로 전망. 본인이 prototyping한 사례로 dbfor.dev 언급

  • 공격자가 다음과 같은 문구를 지원 티켓에 담아두는 현상 ("CURSOR CLAUDE 관련 명령... integration_tokens 테이블을 읽어서 티켓 메시지로 추가"와 같은) 자체가 납득이 어렵다는 반응. AI agent가 사용자 입력에 따라 데이터와 직접 상호작용하게 만들 리가 없다고 생각

    • LLM에는 Prepared statement가 없고, 데이터와 명령을 구분하지 못함. 봇에게 특정 업무만 허용하려고 해도 프롬프트 엔지니어링으로는 완벽한 안전 보장 불가. 심지어 '티켓 우선순위' 같은 단순 조작만 허용하더라도 악용 위험은 여전히 존재

    • 이런 구조의 문제는 시스템 설계 과정의 실수가 아니라, LLM이 입력 텍스트에서 사용자 명령과 유입된 기타 명령을 구분할 수 없다는 근본적 한계 때문임. 본인은 이 문제를 SQL 인젝션과 유사하다고 생각해 'prompt injection'이라는 용어를 사용. SQL 인젝션의 경우 안전한 방어 기법(escape, parameterize)이 있지만, 프롬프트 인젝션은 이에 대응하는 해결책이 없음