AI applications face unique security challenges. Beyond traditional API vulnerabilities, AI APIs expose new attack surfaces: prompt injection, data leakage, and model manipulation. Here's how to secure your AI-powered systems.
The AI Security Landscape
AI APIs introduce attack vectors traditional APIs don't have:
- Prompt injection — Malicious input that manipulates AI behavior
- Data exfiltration — AI accidentally leaking sensitive context
- Token exhaustion — attackers exhausting your quota
- Model extraction — Repeated queries to reverse-engineer the model
- Context poisoning — Injecting malicious context into conversations
Input Validation and Sanitization
`python
import re
from typing import Optional
class InputSanitizer:
Block common prompt injection patterns
BLOCKED_PATTERNS = [
r'ignore\s+previous\s+instructions',
r'ignore\s+all\s+previous',
r'system\s:\s',
r'you\s+are\s+a\s+different',
r'forget\s+everything',
r'#\s*roleplay',
]
MAX_LENGTH = 10000 # Max 10k characters
MAXTOKENSESTIMATE = MAX_LENGTH // 4 # ~2500 tokens
@classmethod
def sanitize(cls, user_input: str) -> tuple[bool, Optional[str], str]:
"""
Returns: (issafe, reason, sanitizedinput)
"""
Check length
if len(userinput) > cls.MAXLENGTH:
return False, f"Input exceeds {cls.MAXLENGTH} chars", userinput[:cls.MAX_LENGTH]
Check for blocked patterns
for pattern in cls.BLOCKED_PATTERNS:
if re.search(pattern, user_input, re.IGNORECASE):
return False, "Blocked pattern detected", ""
Strip control characters
sanitized = re.sub(r'[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]', '', user_input)
return True, None, sanitized
`
Rate Limiting
`python
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
import time
from collections import defaultdict
app = FastAPI()
Simple in-memory rate limiter
class RateLimiter:
def init(self, requestsperminute: int = 60):
self.requestsperminute = requestsperminute
self.requests = defaultdict(list)
def isallowed(self, clientid: str) -> bool:
now = time.time()
minute_ago = now - 60
Clean old entries
self.requests[client_id] = [
t for t in self.requests[clientid] if t > minuteago
]
if len(self.requests[clientid]) >= self.requestsper_minute:
return False
self.requests[client_id].append(now)
return True
ratelimiter = RateLimiter(requestsper_minute=60)
@app.middleware("http")
async def ratelimitmiddleware(request: Request, call_next):
client_id = request.client.host # Or use API key
if not ratelimiter.isallowed(client_id):
return JSONResponse(
status_code=429,
content={"error": "Rate limit exceeded"}
)
response = await call_next(request)
return response
`
API Key Security
`python
import os
import hashlib
import hmac
from typing import Optional
class APIKeyManager:
"""
Never store raw API keys. Always hash them.
"""
def init(self):
self.keystore = {} # In production, use a proper database
def createkey(self, userid: str, scopes: list[str]) -> str:
import secrets
apikey = f"ofox{secrets.token_urlsafe(32)}"
keyhash = self.hashkey(apikey)
self.keystore[key_hash] = {
"userid": userid,
"scopes": scopes,
"created": time.time()
}
Return raw key ONLY ONCE to the user
return api_key
def validatekey(self, apikey: str) -> Optional[dict]:
keyhash = self.hashkey(apikey)
return self.keystore.get(key_hash)
def hashkey(self, key: str) -> str:
return hashlib.sha256(key.encode()).hexdigest()
Usage
key_manager = APIKeyManager()
rawkey = keymanager.create_key("user123", ["chat", "embeddings"])
print(f"Save this key securely: {raw_key}") # Show once
`
Prompt Injection Defense
`python
class PromptInjectionDetector:
"""
Detect attempts to override system behavior through user input.
"""
INJECTION_SIGNALS = [
"ignore previous",
"disregard your",
"new instructions:",
"[INST]",
"<>",
"<>",
"you are now",
"pretend you are",
"forget your",
"system prompt:",
]
@classmethod
def detect(cls, user_input: str) -> bool:
lowerinput = userinput.lower()
for signal in cls.INJECTION_SIGNALS:
if signal.lower() in lower_input:
return True
return False
Usage in your endpoint
@app.post("/chat")
async def chat(request: ChatRequest):
if PromptInjectionDetector.detect(request.messages[-1].content):
Log and block
logger.warning(f"Prompt injection attempt: {request.messages[-1].content[:100]}")
raise HTTPException(status_code=400, detail="Invalid input")
Continue with normal processing
`
Data Isolation in Multi-Tenant Systems
`python
class ConversationContext:
"""
Ensure user data doesn't leak between conversations.
"""
def init(self, userid: str, apikey: str):
self.userid = userid
self.apikey = apikey
self.conversationhistory = []
def add_message(self, role: str, content: str):
self.conversationhistory.append({
"role": role,
"content": content,
"userid": self.userid # Tag with user
})
def get_messages(self) -> list[dict]:
Always filter by user_id to prevent leakage
return [
m for m in self.conversationhistory
if m["userid"] == self.userid
]
def clear_history(self):
Only clear THIS user's history
self.conversationhistory = [
m for m in self.conversationhistory
if m["userid"] != self.userid
]
`
Secure Error Handling
`python
@app.exception_handler(Exception)
async def globalexceptionhandler(request: Request, exc: Exception):
Never expose internal error details in production
logger.error(f"Error: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={
"error": "Internal server error",
Don't include: exc.message, stack trace, API keys
}
)
For API provider errors (like ofox.ai errors)
@app.post("/chat")
async def chat(request: ChatRequest):
try:
result = await callofoxapi(request)
return result
except httpx.HTTPStatusError as e:
Log full error internally
logger.error(f"ofox API error: {e.response.status_code} {e.response.text}")
Return sanitized error to client
raise HTTPException(
status_code=502,
detail="AI service temporarily unavailable"
)
`
Environment Variables (Never Hardcode)
`bash
.env (never commit this file)
OFOXAPIKEY=your-key-here
DATABASE_URL=postgresql://...
JWT_SECRET=your-secret-here
docker-compose.yml (use secrets in production)
environment:
- OFOXAPIKEY=${OFOXAPIKEY} `
`python
Load from environment
from dotenv import load_dotenv
load_dotenv() # In development only
apikey = os.environ.get("OFOXAPI_KEY")
if not api_key:
raise ValueError("OFOXAPIKEY not set")
`
Security Checklist
[ ] Input validation on all user-provided text
[ ] Rate limiting on all endpoints
[ ] API keys hashed (never stored raw)
[ ] Prompt injection detection
[ ] Error messages don't expose internals
[ ] Environment variables for secrets (not hardcoded)
[ ] HTTPS only in production
[ ] Logging without sensitive data
[ ] Regular dependency audits (pip audit, npm audit)
Getting Started
Build secure AI applications with ofox.ai — their API includes built-in security features and 99.9% uptime guarantee.
👉 Get started with ofox.ai
This article contains affiliate links.
Tags: security,api,ai,programming,developer
Canonical URL: https://dev.to/zny10289
Top comments (0)