# VC-073 · Vektör araması başka kiracıların belgelerini model bağlamına katıyor

Sohbet uç noktası oturum istiyor ama benzerlik araması ortak belge havuzunun tamamında çalışıyor. Başka kiracıya ait yakın sonuçlar kullanıcının sorusuna cevap üretmek için modele veriliyor.

- Önem: ACİL. Etkisi büyük. Sıradan bir üye hesabı yeter ve tarayıcıdan görülür.
- Önem notu: Hesaplı kullanıcının sohbetten başka kuruluşların özel belgelerine ulaşabildiği ortak arama havuzu varsayılır. Yalnız herkese açık belgeler varsa aynı gizlilik etkisi oluşmaz. Kaynak tabloyu korumak, ayrı parça tablosunu ve ayrı arama servisini kendiliğinden korumaz.
- Eksen ve kategori: Güvenlik, 10 Uygulama içi LLM özellikleri
- Yığın: Node.js, Supabase, Her yığın
- Yapay zekâ kodunda: ölçülmedi. Dayanak: uzman görüşü.
- Ne zaman bakılır: LLM özelliği eklerken, Kişisel veri toplamadan önce, Her ay
- CWE: CWE-862
- OWASP Top 10:2025: A01:2025 Broken Access Control
- OWASP LLM: LLM09:2026
- Checklist ifadesi: Vektör araması yalnız kullanıcının kendi kiracısına ait belgeleri getiriyor.
- Son inceleme: 4 Ekim 2026, Komünite editörlüğü
- Adres: https://vibecheck.komunite.com.tr/madde/vektor-aramasinda-kiraci-verileri-karisiyor

## 60 saniyelik kontrol

Yalnız kendi uygulamanda ya da yazılı izin aldığın sistemde dene. Bu bir sızma testi değildir.

1. Ayrı iki test kiracısına aynı konulu ve ayırt edici yapay işaretli belgeler ekle.
2. Bir kiracıyla arama yapıp modele gönderilecek belge parçalarını yerelde yakala.
3. Diğer kiracının parçasının başlık, metin ve kaynak bağlantısında bulunmadığını doğrula.
4. Kiracı seçiminin model argümanından değil sunucuda doğrulanmış üyelikten geldiğini incele.
5. Üyeliği kaldırılan test hesabının eski kiracı kapsamıyla sonuç alamadığını kontrol et.

## Ne oluyor

Ekip belgelerini arayan bir asistan kuruyorsun. Kullanıcı oturum açıyor, sorusu vektöre çevriliyor ve en yakın belge parçaları modele gönderiliyor. Belgeler yönetim panelinde doğru ekibin altında görünüyor. Fakat arama işlevi ortak vektör tablosunun tamamında çalışıyorsa paneldeki ayrım modelin okuyacağı bağlamı korumuyor.

Benzerlik, erişim hakkını ifade etmez. Başka ekibin belgesi soruya daha yakın olabilir. Arama bu belgeyi seçtiğinde model onu cevap için kullanabilecek duruma gelir. Kullanıcıdan belge kimliği istemeyen doğal dil araması, kayıt numarası tahmin etmeye gerek kalmadan aynı sınırı aşabilir. Modelin başka ekibe ait bilgiyi paylaşmamasını istemek, bilginin bağlama girişini engellemez.

Kaynak belgenin yetkisi ile ondan üretilen parçaların yetkisi birlikte taşınmalıdır. Parçalama sırasında ekip bilgisi kaybolursa yeni arama tablosu ayrı bir veri yolu açar. Aynı durum yeniden sıralama, kaynak bağlantısı üretme ve anlamsal önbellek aşamalarında da ortaya çıkabilir. Sorgunun başından cevap için seçilen son parçaya kadar kullanıcı kapsamı korunmalıdır.

## Gerçek olay

Bu maddede belirli bir ürüne ait doğrulanmış kiracılar arası sızıntı olayı sunulmuyor. [OWASP LLM09:2026](https://raw.githubusercontent.com/GenAI-Security-Project/GenAI-LLM-Top10/main/2026/final/LLM09_VectorAndEmbeddingWeaknesses.md), ortak benzerlik aramasında erişim kapsamının sorgu içinde uygulanmasını ele alır. Sonuçlar geldikten sonra filtreleme, erişim kararını arama sonrasına bırakır. Burada belgenin doğrudan model bağlamına girdiği desen incelenir, zamanlama saldırısı ölçümü yapılmaz.

[Supabase'in RAG yetki rehberi](https://supabase.com/docs/guides/ai/rag-with-permissions), belge parçalarını kaynak belgenin sahipliğine bağlayan RLS örneği verir. Yerel deney daha küçük bir düzen kullanır. Yapay sayısal koordinatlarla SQLite üzerinde yakınlık sıralaması yapılır. Başka kiracıya ait en yakın kayıt iyi sürümde seçilmez. Bu deney Supabase, pgvector veya gerçek embedding modeli çalıştırıldığı anlamına gelmez.

## Yapay zekâ bunu neden üretiyor

**Arama örneği tek havuz varsayar.** Ajan genel bir benzerlik sorgusunu uygulamaya ekleyebilir. Küçük örnekte bütün belgeler aynı kişiye ait olduğu için ek kapsam görünmez. Ürün ekipli hale geldiğinde sorgu değişmeden kalır. Belgelerin yükleme ekranında ayrılması arama işlevinin de aynı ayrımı yaptığı izlenimini verebilir.

**Parça tablosu teknik ayrıntı sayılır.** Kaynak belgede sahip alanı bulunur ama metin parçaları yalnız belge numarası ve vektörle saklanır. Ajan performansa veya cevap kalitesine odaklanırken erişim ilişkisinin bu yeni tabloda nasıl kurulacağını atlayabilir. Kaynak tabloya uygulanan kural ayrı tabloya kendiliğinden taşınmaz. Arama yolunu gerçek çağrı kimliğiyle incelemek gerekir.

**Servis hesabı entegrasyonu kolaylaştırır.** Sunucudaki geniş kimlik bütün belgeleri okuyabildiği için ilk bağlantı sorunsuz çalışır. Kullanıcı kimliği daha sonra prompta bilgi olarak eklenebilir. Ancak prompttaki kimlik veritabanının erişim kararı değildir. Aramanın hangi yetkiyle yapıldığı ayrıca belirlenmelidir. Oturum kontrolü yalnız konuşmaya kimin başladığını gösterir.

**Cevap testi veriyi geç görür.** Asistanın son yanıtında yabancı bilgi görünmeyince sınırın korunduğu sanılabilir. Oysa başka ekibin parçası bağlama girmiş, model bu denemede kullanmamış olabilir. Ara katmandaki seçilmiş parçaları incelemek hatayı daha doğrudan yakalar. Bunlar olası üretim mekanizmalarıdır. AI tarafından üretilen arama kodlarının hata sıklığı hakkında ölçüm veya oran iddiası değildir.

## Etki

Başka ekibin özel sözleşmesi, iç notu veya ürün planı cevap içinde görünebilir. Kaynak gösterimi açıksa belge başlığı ve bağlantısı da açığa çıkabilir. Belgenin tüm metninin dönmesi gerekmez. Kullanıcının erişmemesi gereken bir parçanın model bağlamına taşınması zaten veri sınırının aşıldığını gösterir.

Yanlış ekipten gelen içerik, gizlilik sorununa ek olarak yanlış cevap üretebilir. Kullanıcı kendi ekibinin politikasını sorduğunda başka ekibin kuralını öğrenebilir. Sonradan yalnız kaynak bağlantısını gizlemek iki sorunu da çözmez. Ortak havuz gerçekten kamuya açık içerikten oluşuyorsa kiracı ayrımı aynı gizlilik şartıyla değerlendirilmez, veri sınıflandırması açık olmalıdır.

## Nasıl anlarsın

İki test kiracısına aynı konulu ama farklı yapay işaretler taşıyan belgeler ekle. Bir kiracının hesabıyla sor ve modele gönderilecek parçaları yakala. Başka kiracının metni, başlığı veya bağlantısı bulunmamalı. Yalnız son yanıtı kontrol etmekle yetinme. Gerçek müşteri belgeleriyle sızıntı deneyi yapman gerekmez.

Kodda benzerlik sorgusunun kapsamına bak. Kiracı alanı modelin argümanından mı geliyor? Üyelik sunucuda doğrulanıyor mu? En yakın sonuçlar seçildikten sonra mı filtreleniyor? Yerel örnekte yabancı belge soruya daha yakındır. Buna rağmen izinli belgeler dönmelidir. Üyelik kaldırıldığında aynı oturum kapsamıyla sonuç alınamaması da sınanır.

## Nasıl düzeltirsin

1. **Parçanın yetkisini koru.** Kaynak belgeyle parça arasındaki ilişkiyi ve kiracı bilgisini sakla. Belge taşınırken, paylaşımı değişirken veya silinirken arama verisinin ne zaman güncelleneceğini belirle. Eski kopyalar için de erişim kararını koru.
2. **Kapsamı sorguya koy.** Kullanıcı ve seçili kiracıyı sunucunun doğruladığı bağlamdan al. Geçerli üyeliği kontrol ederek izinli kayıtlar üzerinde sıralama yap. Örnek sorgu kiracı ve üyelik koşulunu aynı SQL içinde uygular. İstemcinin gönderdiği kiracı numarası kendi başına izin vermez.
3. **Gerçek veri yolunu doğrula.** Supabase kullanıyorsan parça tablosunun RLS politikasını ve arama fonksiyonunun rolünü incele. Geniş servis kimliğiyle alınan sonuç, kullanıcı rolünün güvenli olduğunu kanıtlamaz. Yerel SQLite örneği RLS kurmaz, üretim rol testinin yerini tutmaz.
4. **Arama sonrasını bağla.** Yeniden sıralama, model bağlamı, önbellek ve kaynak gösterimi aynı yetki kapsamıyla çalışsın. Kiracıya göre sonuç üretip herkese ortak önbellekten servis etmek sınırı yeniden açar. İzinli normal aramayı ve reddedilmesi gereken çapraz aramayı birlikte koru.

## Bir daha olmasın

Arama kalitesi testlerinin yanına iki kiracılı erişim testi ekle. Modelin cevabıyla birlikte ona verilen kaynak parçalarını da değerlendir.

## Sınır

Bu madde vektör aramasındaki kiracı ve belge erişimini kapsar. Belgelerin içine yerleştirilen talimatlar, embedding verisinin tersine çıkarılması ve arama kalitesi ayrı konulardır. Sorgu filtresi bütün zamanlama yan kanallarının yokluğunu kanıtlamaz. Çok hassas veride ayrı indeks veya ayrı veri alanı gereksinimi ayrıca değerlendirilmelidir.

## Düzeltme kodları

### Node.js: Arama sorgusunda kiracı ve üyelik

Önce:

```js
// arama/parcalar.js, açıklama amaçlı. Koordinatlar yapay iki boyutlu vektördür.
import { z } from 'zod';
const Query = z.object({
  x: z.number().min(-10).max(10), y: z.number().min(-10).max(10),
}).strict();
export function retrieve(db, session, raw) {
  if (!session?.userId || !session?.tenantId) throw new Error('Oturum gerekli');
  const { x, y } = Query.parse(raw);
  // Oturum vardır, fakat arama bütün kiracıların parçalarını okur.
  return db.prepare(`
    SELECT id, body FROM chunks
    ORDER BY ((x - ?) * (x - ?) + (y - ?) * (y - ?)), id
    LIMIT 2
  `).all(x, x, y, y);
}
```

Sonra:

```js
// arama/parcalar.js, açıklama amaçlı. Koordinatlar yapay iki boyutlu vektördür.
import { z } from 'zod';
const Query = z.object({
  x: z.number().min(-10).max(10), y: z.number().min(-10).max(10),
}).strict();
export function retrieve(db, session, raw) {
  if (!session?.userId || !session?.tenantId) throw new Error('Oturum gerekli');
  const { x, y } = Query.parse(raw);
  // session istemci gövdesi değildir, sunucuda doğrulanmış bağlamdır.
  return db.prepare(`
    SELECT c.id, c.body FROM chunks c
    WHERE c.tenant_id = ? AND EXISTS (
      SELECT 1 FROM memberships m
      WHERE m.tenant_id = c.tenant_id AND m.user_id = ?
    )
    ORDER BY ((c.x - ?) * (c.x - ?) + (c.y - ?) * (c.y - ?)), c.id
    LIMIT 2
  `).all(session.tenantId, session.userId, x, x, y, y);
}
```

Düzeltmeyi kanıtlayan test:

```js
// arama/parcalar.test.mjs, açıklama amaçlı. Gerçek embedding veya LLM yok.
import test from 'node:test';
import assert from 'node:assert/strict';
import { DatabaseSync } from 'node:sqlite';
const { retrieve } = await import(process.env.ORNEK_DOSYA);
test('en yakın yabancı parça bağlama girmez, izinli sonuçlar korunur', () => {
  const db = new DatabaseSync(':memory:');
  try {
    db.exec(`CREATE TABLE chunks(id TEXT PRIMARY KEY, tenant_id TEXT, body TEXT, x REAL, y REAL);
      CREATE TABLE memberships(user_id TEXT, tenant_id TEXT, PRIMARY KEY(user_id, tenant_id));
      INSERT INTO memberships VALUES ('u1', 'a'), ('u2', 'b');
      INSERT INTO chunks VALUES ('b1','b','YABANCI_ISARET',0,0),
        ('b2','b','YABANCI_EK',0.1,0), ('a1','a','BIZIM_ILK',1,0), ('a2','a','BIZIM_IKINCI',2,0);`);
    const session = { userId: 'u1', tenantId: 'a' };
    const context = retrieve(db, session, { x: 0, y: 0 });
    assert.deepEqual(context.map(row => row.id), ['a1', 'a2']);
    assert.equal(JSON.stringify(context).includes('YABANCI'), false);
    assert.throws(() => retrieve(db, session, { x: 0, y: 0, tenantId: 'b' }));
    assert.deepEqual(retrieve(db, { userId: 'u1', tenantId: 'b' }, { x: 0, y: 0 }), []);
    assert.deepEqual(retrieve(db, { userId: 'u2', tenantId: 'b' }, { x: 0, y: 0 })
      .map(row => row.id), ['b1', 'b2']);
    db.prepare('DELETE FROM memberships WHERE user_id = ?').run('u1');
    assert.deepEqual(retrieve(db, session, { x: 0, y: 0 }), []);
    assert.throws(() => retrieve(db, null, { x: 0, y: 0 }));
  } finally { db.close(); }
});
```

## Ajan kuralı (AGENTS.md)

```md
## Vektör aramasında kiracı karışıyor (vibecheck VC-073)
- Belge parçaları kaynak belgenin erişim kapsamını taşır.
- Kiracı ve üyelik denetimi arama sorgusunda uygulanır.
- Model veya istemci argümanı aramanın yetki kapsamını belirlemez.
- Sonuç sonrasında filtreleme tek erişim kontrolü olarak kullanılmaz.
- Model bağlamı ve kaynak bağlantıları iki ayrı kiracıyla test edilir.
- Önbellek ve yeniden sıralama yolları aynı erişim kapsamını korur.
```

## Kaynaklar

1. [LLM09:2026 Vector and Embedding Weaknesses](https://raw.githubusercontent.com/GenAI-Security-Project/GenAI-LLM-Top10/main/2026/final/LLM09_VectorAndEmbeddingWeaknesses.md), OWASP
2. [RAG with Permissions](https://supabase.com/docs/guides/ai/rag-with-permissions), Supabase
3. [CWE-862: Missing Authorization](https://cwe.mitre.org/data/definitions/862.html), MITRE
4. [Node.js SQLite parameter binding](https://nodejs.org/api/sqlite.html), Node.js
5. [Zod Defining Schemas](https://zod.dev/api), Zod

---

vibecheck · Komünite editörlüğü. Metin CC BY 4.0, prompt ve kural parçaları MIT-0. Kaynak: https://vibecheck.komunite.com.tr/madde/vektor-aramasinda-kiraci-verileri-karisiyor
