다중 벡터 문서 인덱스만으로 원본 페이지가 복원된다
Inverting Multi-Vector Visual Document Indices
무엇인가
ColPali로 대표되는 다중 벡터 시각 문서 검색기는 페이지 한 장을 약 1,000개의 패치 벡터로 인코딩해 벡터 데이터베이스에 저장한다. 이 인덱스는 흔히 제3자가 운영하는 저장소에 맡겨지는데, 벡터만 보고 페이지를 읽을 수 있는 사람은 없으니 원본 문서보다 덜 민감한 데이터로 취급되기 쉽다. 이 논문은 그 가정에 반박한다. 인덱스는 패치당 벡터 하나를 래스터 순서로 보관하고, 각 벡터는 문서를 읽도록 사전학습된 비전-언어 모델이 페이지 전체 맥락에서 계산한 것이므로, 저장소를 운영하거나 침해한 사람이 인덱스만으로 페이지를 재현할 수 있다는 가설을 세운다. 근거는 세 가지다. 벡터의 위치가 페이지 레이아웃을 그대로 담고 있고, 각 벡터가 자기 패치의 국소 정보와 페이지의 전역 정보를 함께 지니며, 인코더가 수천만 건의 OCR 샘플과 레이아웃 파싱된 PDF로 사전학습됐다는 점이다.
어떻게 동작하나
위협 모델은 제로 사이드 정보를 요구한다. 공격자는 저장된 인덱스 외에 페이지의 원본, 메타데이터, shape 어느 것도 갖지 않는다. 문제는 저장된 인덱스가 생성 과정의 세 가지 사실을 숨긴다는 것이다. 어떤 인코더가 만들었는지, 페이지 shape가 n_h × n_w 중 무엇인지, 그리고 셔플된 인덱스라면 벡터 순열 π가 무엇인지다. 저장 구성은 세 가지로 나뉜다. 인코더 출력 순서 그대로인 raw, 계층적 토큰 풀링으로 f=3 또는 f=9 비율로 벡터를 합친 pooled, 페이지마다 무작위 순열로 순서를 섞은 shuffled다. late interaction 점수는 벡터 순서에 의존하지 않으므로 셔플은 검색 품질을 바꾸지 않는다. 공격의 목표는 두 갈래로 측정된다. OCR이 복원 페이지에서 읽어내는 단어와 민감 토큰의 비율인 내용 유출, 그리고 복원 페이지가 저장된 P개 페이지 중 자기 원본을 1위로 랭크하는지 보는 신원 유출이다.
무엇과 다른가
핵심 도구는 조건부 플로 매칭 인버터다. 텍스트-이미지 모델 Qwen-Image의 구조를 그대로 쓰되 조건을 텍스트 프롬프트 대신 저장된 인덱스로 바꾸고, 생성 대상을 페이지 이미지로 바꿨다. 페이지는 고정된 VAE의 잠재 공간(공간 인자 8, 채널 16)에서 rectified flow 경로를 따라 생성된다. 손실은 v_θ(x_t, t, C)와 (x_0 - x_1)의 제곱 오차인데, 이는 회귀가 아니라 조건부 분포에서 샘플링하기 위한 것이다. 회귀 디코더의 L2 최적해는 조건부 평균이라 인덱스가 모호하게 남긴 모든 글리프가 뭉개지기 때문이다. 지각 손실이나 적대적 손실은 일부러 넣지 않는다. 각각 고유한 사전확률을 끌어들여 인덱스에 없는 텍스트를 써넣을 수 있기 때문이다. 조건은 10% 확률로 드롭되고 학습 가능한 널 토큰으로 대체되며, 추론 시에는 무조건부와 조건부 속도를 γ=4로 외삽하는 classifier-free guidance를 50번의 오일러 스텝에 걸쳐 적분한 뒤 고정 VAE로 디코딩한다. 인버터 본체는 이중 스트림 MMDiT로, 텍스트 스트림 자리에 인덱스가 들어가 조건 토큰과 이미지 토큰이 모든 블록에서 함께 어텐션된다. 위치는 입력 shape로부터 계산되는 rotary 임베딩으로만 들어가므로 하나의 가중치 세트가 모든 페이지 shape를 처리한다. 변형은 두 가지다. ordered 인버터는 raw 인덱스의 각 벡터에 실제 2차원 위치를 부여하고, set 인버터는 조건의 rotary 임베딩을 빼서 구성상 순열 불변으로 만든다. 후자가 pooled 인덱스와, 위치 모델 없이 셔플된 인덱스를 읽는다.
어떻게 쓰나
인덱스가 숨긴 세 사실은 인덱스 자체에서 추론된다. 인코더 식별은 두 단계다. 먼저 후보 인코더 중 출력의 차원, 단위 노름, 벡터 개수가 맞는 것만 남기고, 남은 후보마다 공개 학습 페이지 2,000장의 참조 집합을 인코딩한다. 저장된 인덱스마다 평균 풀링 벡터의 코사인으로 최근접 페이지를 찾고, 각 저장 벡터와 최근접 참조 벡터 사이 평균 코사인으로 재정렬해 가장 높은 점수를 준 후보를 고른다. 페이지 shape는 raw 인덱스의 경우 벡터 개수 N = n_h n_w라는 제약에 주기성 단서를 더한다. 같은 열의 인접한 두 행에 있는 벡터는 서로 닮는 경향이 있으므로 행 너비 n_w는 수열의 주기이고, 시차 w에서의 평균 코사인 유사도 s(w)를 종횡비 창 안의 약수들에 대해 최대화해 n_w를 정한다. pooled 인덱스에는 이런 주기가 없으므로 벡터 개수와 양립하는 소수 후보 중에서 순열 불변 집합 분류기가 하나를 고른다. 셔플된 인덱스는 위치 모델의 종횡비 헤드가 shape를 추정한다. 순서 복원은 라벨이 필요 없다. 공개 페이지를 공개 인코더에 통과시키면 각 벡터의 행과 열이 자동으로 정답이 된다. 위치 인코딩 없는 Transformer 인코더를 집합 위에 돌려 각 벡터의 정규화된 행·열을 제곱 오차로 회귀시키고, 요약 토큰이 페이지 종횡비를 함께 회귀한다. 헝가리안 알고리즘이 예측 좌표를 n_h × n_w 슬롯에 일대일로 배정하고, 재정렬된 인덱스는 그대로 ordered 인버터로 들어간다.
전제와 한계
실험은 공개 인코더 두 개를 공격한다. 주 대상 E_A는 Qwen3-VL 기반 ColPali 스타일 late-interaction 검색기 Tomoro-ColQwen3-8B로, 패치당 320차원 백터를 내놓고 페이지를 32n_w × 32n_h 픽셀로 리사이즈한다. 일반화 확인용 E_B는 다른 팀이 다른 백본으로 파인튜닝한 ColQwen3.5-4.5B로 입력 해상도가 더 낮다. 인버터는 VisRAG 학습 코퍼스, ColPali 학습셋, vdr-multilingual-train, VDR-MEGA-2를 중복 제거한 682,818장으로 E_A용을, 앞의 세 컬렉션 346,770장으로 E_B용을 학습한다. 평가는 ViDoRe v3의 8개 전문 도메인 19,252페이지 중 도메인별 250장씩 균등 추출한 고정 2,000페이지(11개 shape)에서 이뤄지며, 학습 데이터와 겹치는 페이지는 2,000장 중 8장(0.4%)뿐이고 이를 제거해도 수치는 변하지 않는다. 인코더 식별은 차원 128·320·640이 섞인 공개 검색기 13종 풀에서 페이지당 한 번씩, 총 26,000번의 결정에서 전부 정답이었다. shape 추정도 raw 99.2%, 풀링 인자 3과 9에서 각각 99.1%와 95.7%, 셔플 99.95%로 거의 정확했다.
raw 인덱스에서 복원한 페이지는 참조 단어의 47.4%를 되살리고 문자 단위 NED 0.292를 기록했다. kNN 베이스라인은 0.858, 조건을 뺀 널 모델은 0.958이었다. 민감 토큰 회수율은 45.0%로 kNN의 14.6%를 크게 앞섰고, 복원 페이지를 질의로 써서 19,252개 인덱스에 대해 랭킹하면 자기 원본을 1위로 올린 비율이 98.4%였다. 인덱스 생성에 관여하지 않은 독립 판정 인코더로 채점해도 97.7%로, 원본 페이지 자체의 99.6%에 근접했다. 널 모델은 단어의 0.1%만 복구했고, 같은 인덱스에서 시드를 달리해 뽑은 두 샘플끼리의 단어 F1(0.476)이 각 샘플과 원본의 일치도(0.480)와 비슷해, 공통으로 나온 텍스트는 사전확률이 지어낸 것이 아니라 원본의 것임을 보였다. 보호 기법은 결과가 갈린다. pooled 인덱스는 단어 회수율이 인자 3에서 7.6%, 인자 9에서 8.1%로 kNN 베이스라인 아래로 떨어졌고 2,000장 중 1위로 올린 페이지가 각각 21장과 10장뿐이었다. 위치 모델 없이 셔플만 한 경우도 단어 회수율 8.4%, 재식별 3.8%로 비슷한 수준이었다. 그러나 순서는 복원된다. 위치 모델은 셔플된 벡터를 평균 절대 오차 1.8행·4.5열로 배치했고(무작위 순서는 12.6행·11.3열), 재정렬된 인덱스를 ordered 인버터에 넣자 재식별이 3.8%에서 93.5%로 뛰었다. 독립 판정으로는 87.7%, 단어 회수율 23.1%, 민감 토큰 회수율 21.2%였다. 두 번째 인코더 E_B에서는 같은 공격을 그대로 적용해 raw 인덱스에서 재식별 70.2%(kNN 15.4%), 독립 판정 60.5%를 얻었지만, 셔플은 0.6%로 떨어지고 위치 모델을 붙여도 11.2%에 그쳐 kNN 베이스라인을 넘지 못했다. 단어 회수율도 7.9%로 베이스라인의 22.3%에 미달했다. 저자들은 E_A용 인버터를 같은 세 컬렉션으로 학습하면 단어 55.5%, 재식별 98.9%가 나온다며, 차이가 공격자 데이터가 아니라 인코더 자체에 있다고 본다.
실무적으로 이 논문이 던지는 메시지는 저장 위치와 접근 등급에 관한 것이다. 인덱스가 페이지와 분리돼 보관되는 순간, 즉 호스팅 벡터 DB의 식별자가 접근 통제된 별도 스토리지의 페이지 이미지를 가리키거나, 인덱스와 문서에 서로 다른 접근 등급이 매겨지거나, 인덱스 스냅샷과 백업이 따로 도는 구성에서는 침입자가 손에 넣는 페이지의 유일한 사본이 그 인덱스가 된다. raw 인덱스는 인코딩 대상 문서와 같은 수준으로 보호해야 한다. 셔플은 검색 품질을 건드리지 않으면서 값싼 보호처럼 보이지만, 위치 모델 하나로 재식별 대부분이 되살아나므로 신뢰할 만한 방어가 아니다. 반면 풀링은 이 논문의 공격으로는 뚫리지 않았고, 저자들은 이를 열린 문제로 남겨둔다. 벡터 DB를 제3자에게 맡기거나 인덱스만 별도 티어로 내보내는 설계를 검토 중이라면, 이 논문의 위협 모델이 정확히 그 구성에 해당한다는 점을 먼저 확인해야 한다.
저자들이 밝힌 한계는 분명하다. 공격 대상 인코더 두 개가 모두 Qwen 백본 위의 ColPali 스타일 late-interaction 검색기라 단일 모델 패밀리에서만 검증됐고, 인코더 식별도 13종 공개 인코더 풀에서만 평가됐다. 비공개 인코더가 만든 저장소는 범위 밖이다. 보고된 유출 수치는 여러모로 보수적이다. ordered 인버터의 검증 손실은 10만 스텝에서도 계속 내려가 과적합 기미가 없어 더 큰 모델이나 긴 학습 일정이면 수치가 올라갈 수 있고, 더 작고 잘 맞는 학습셋만으로도 단어 회수율이 0.474에서 0.555로 뛰었다. guidance scale도 분포 내 검증 페이지 100장에서 한 번 고른 값을 모든 설정에 그대로 적용했다. 지표 자체의 한계도 있다. OCR 기반 지표는 원본 페이지의 OCR 전사문을 정답으로 삼는데 그 전사문에도 오류가 있을 수 있고, 민감 토큰은 정규식 휴리스틱으로 정의돼 사람이 실제로 민감하다고 볼 토큰인지 확인하는 인간 연구는 없었다. 복원된 페이지의 어느 부분이 맞는지 검증할 방법도 없다. 인버터가 학습된 분포에서 샘플링하므로 아무것도 복구하지 못했는데도 그럴듯한 페이지를 그려낼 수 있기 때문이다. 마지막으로 공격과 방어의 범위가 좁다. pooled 벡터의 위치 복원은 시도하지 않았으므로 풀링이 역산을 막는다는 결론은 이 논문의 공격에 한정되며, 가산 노이즈, 양자화, 키 기반 랜덤 투영, 암호화된 late-interaction 검색, 저장소 접근 제어는 평가되지 않았다. 저자들은 코드와 평가 매니페스트, 프로토콜은 공개하되 학습된 인버터는 배포하지 않겠다고 밝힌다.