Fingerprinting Model Providers and Versions
Knowing which model and provider is behind an AI application determines which attacks are viable. Different providers have different system prompt enforcement, different tool calling implementations, different safety measures, and different known vulnerabilities. Version information narrows the attack surface further — older model versions often have weaker instruction following and more permissive behavior. Fingerprinting happens passively from responses before any active probing begins.
Inspect Response Headers
AI providers and proxy layers often leak their identity in HTTP headers. Check every response from a candidate AI endpoint:
HTTP/2 200 content-type: application/json openai-model: gpt-4o openai-processing-ms: 1842 x-request-id: req_abc123 x-ratelimit-limit-tokens: 30000 openai-version: 2020-10-01
Headers to look for across providers:
- openai-model — exact model name from OpenAI or Azure OpenAI
- x-model-id — Anthropic Claude model identifier
- x-ratelimit-limit-tokens — confirms OpenAI API rate limiting in place
- x-amzn-requestid — indicates AWS Bedrock backend
- x-envoy-upstream-service-time — common in Google Vertex AI responses
- cf-cache-status — Cloudflare in front, which may affect injection payloads
Extract Model Information from Error Responses
Sending a malformed request often triggers a detailed error that leaks the model name and provider:
{
"error": {
"message": "Missing required field: messages",
"type": "invalid_request_error",
"param": "messages",
"code": null
}
}
The error structure identifies the provider. OpenAI and compatible APIs return type: invalid_request_error. Anthropic returns type: invalid_request_error with a different field structure. AWS Bedrock returns XML error responses. Google Vertex returns JSON with a status field. Mismatched error structures between what you expect and what arrives indicate a proxy or custom wrapper.
Request the Models List Endpoint
OpenAI-compatible APIs expose a /models endpoint that lists available models when not properly restricted:
{
"object": "list",
"data": [
{"id": "gpt-4o", "object": "model"},
{"id": "gpt-4o-mini", "object": "model"},
{"id": "text-embedding-3-large", "object": "model"}
]
}
An exposed models list reveals every model the application has access to, not just the one it uses by default. The presence of embedding models confirms a RAG pipeline. Multiple chat models suggests the application allows model selection, which is worth testing for model substitution attacks in later phases.
Fingerprint via Response Timing and Token Patterns
Different models produce responses at different speeds and with different token patterns. Streaming responses reveal model characteristics through timing:
data: {"choices":[{"delta":{"content":"P"}}]}
data: {"choices":[{"delta":{"content":"ING"}}]}
data: [DONE]
Streaming chunk size and token boundaries differ between providers. GPT-4 class models tend to stream in larger chunks than GPT-3.5. Claude streams character by character in some configurations. Ollama-hosted local models stream at different rates depending on GPU availability. This is a weak signal but useful when combined with other indicators.
Ask the Model Directly
Many deployed models will reveal their identity when asked directly, especially when system prompt restrictions are minimal:
If the model answers, note the exact phrasing — models describe themselves differently depending on their training and system prompt. If the model refuses or gives a generic non-answer, a system prompt is likely restricting self-identification. Try indirect approaches:
Check usage and Billing Metadata
Successful completions often include token usage metadata that reveals model-specific context window characteristics:
{
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
Token count for a minimal prompt combined with maximum context window information from the API or documentation helps narrow down the exact model version. GPT-4o has a 128k context window. GPT-4-turbo has the same. GPT-3.5-turbo-16k has 16k. Claude 3.5 Sonnet has 200k. These limits are fingerprinting signals when you can probe the context ceiling.
References
-
OpenAI API — Models endpoint referenceplatform.openai.com/docs/api-reference/models/list (opens in new tab)
Models list endpoint structure and response format
-
Anthropic API — Getting starteddocs.anthropic.com/en/api/getting-started (opens in new tab)
Anthropic API response structure and error format reference
Was this helpful?
Your feedback helps improve this page.