mirror of
https://github.com/Shiva108/ai-llm-red-team-handbook.git
synced 2026-05-14 12:48:16 +02:00
b3d3bac51f
- Extracted all code examples from handbook chapters - Organized into 15 attack categories - Created shared utilities (api_client, validators, logging, constants) - Added workflow orchestration scripts - Implemented install.sh for easy setup - Renamed all scripts to descriptive functional names - Added comprehensive README and documentation - Included pytest test suite and configuration
84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
The `AI_Recon_Scanner`
|
|
|
|
Source: Chapter_39_AI_Bug_Bounty_Programs
|
|
Category: compliance
|
|
"""
|
|
|
|
import aiohttp
|
|
import asyncio
|
|
from typing import Dict, List
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
class AIReconScanner:
|
|
"""
|
|
Fingerprints AI backends by analyzing HTTP headers and
|
|
404/405 error responses for specific signatures.
|
|
"""
|
|
|
|
def __init__(self, targets: List[str]):
|
|
self.targets = targets
|
|
self.signatures = {
|
|
"OpenAI": ["x-request-id", "openai-organization", "openai-processing-ms"],
|
|
"Anthropic": ["x-api-key", "anthropic-version"],
|
|
"HuggingFace": ["x-linked-model", "x-huggingface-reason"],
|
|
"LangChain": ["x-langchain-trace"],
|
|
"Azure OAI": ["apim-request-id", "x-ms-region"]
|
|
}
|
|
|
|
async def scan_target(self, url: str) -> Dict:
|
|
"""Probes a URL for AI-specific artifacts."""
|
|
results = {"url": url, "backend": "Unknown", "confidence": 0}
|
|
|
|
try:
|
|
async with aiohttp.ClientSession() as session:
|
|
# Probe 1: Check Headers
|
|
async with session.get(url, verify_ssl=False) as resp:
|
|
headers = resp.headers
|
|
for tech, sigs in self.signatures.items():
|
|
matches = [s for s in sigs if s in headers or s.lower() in headers]
|
|
if matches:
|
|
results["backend"] = tech
|
|
results["confidence"] += 30
|
|
results["signatures"] = matches
|
|
|
|
# Probe 2: Check Standard API Paths
|
|
api_paths = ["/v1/chat/completions", "/api/generate", "/v1/models"]
|
|
for path in api_paths:
|
|
full_url = f"{url.rstrip('/')}{path}"
|
|
async with session.post(full_url, json={}) as resp:
|
|
# 400 or 422 usually means "I understood the path but you sent bad JSON"
|
|
# This confirms the endpoint exists.
|
|
if resp.status in [400, 422]:
|
|
results["endpoint_found"] = path
|
|
results["confidence"] += 50
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
return {"url": url, "error": str(e)}
|
|
|
|
async def run(self):
|
|
tasks = [self.scan_target(t) for t in self.targets]
|
|
return await asyncio.gather(*tasks)
|
|
|
|
# Usage
|
|
# targets = ["https://chat.target-corp.com", "https://api.startup.io"]
|
|
# scanner = AIReconScanner(targets)
|
|
# asyncio.run(scanner.run())
|
|
|
|
|
|
def main():
|
|
"""Command-line interface."""
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
|
|
args = parser.parse_args()
|
|
|
|
# TODO: Add main execution logic
|
|
pass
|
|
|
|
if __name__ == "__main__":
|
|
main() |