OWASP Top 10 2025: Securing Web Applications in the AI Era
OWASP Top 10 2025: Securing Web Applications in the AI Era
As web applications become more complex and AI-driven, security threats continue to evolve. Let's explore the OWASP Top 10 vulnerabilities for 2025 and learn how to protect against them.
1. Broken Access Control
Access control vulnerabilities have moved up to the top position due to the increasing complexity of modern applications.
Common Issues:
# Insecure direct object reference
@app.get("/api/users/{user_id}/data")
async def get_user_data(user_id: int, current_user: User = Depends(get_current_user)):
# BAD: No verification if current_user can access user_id's data
return await db.get_user_data(user_id)
# GOOD: Verify access rights
@app.get("/api/users/{user_id}/data")
async def get_user_data(user_id: int, current_user: User = Depends(get_current_user)):
if not await can_access_user_data(current_user, user_id):
raise HTTPException(status_code=403, detail="Access denied")
return await db.get_user_data(user_id)
2. AI/ML Model Injection
A new entry reflecting the rise of AI-powered applications.
Prevention:
from typing import List
import tensorflow as tf
def sanitize_model_input(input_data: List[float]) -> List[float]:
"""Sanitize and validate ML model inputs"""
# Ensure inputs are within expected ranges
return [max(min(x, 1.0), -1.0) for x in input_data]
def predict_with_safety(model: tf.keras.Model, input_data: List[float]) -> float:
sanitized_input = sanitize_model_input(input_data)
prediction = model.predict([sanitized_input])
return validate_prediction(prediction)
3. Cryptographic Failures
Includes weak encryption and poor key management.
Best Practices:
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
def generate_key(password: str, salt: bytes) -> bytes:
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=480000,
)
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
return key
def encrypt_sensitive_data(data: str, key: bytes) -> str:
f = Fernet(key)
return f.encrypt(data.encode()).decode()
4. Injection Vulnerabilities
SQL, NoSQL, and Command injection remain critical threats.
Prevention:
from sqlalchemy import text
from typing import List
# BAD: SQL Injection vulnerable
async def get_users(name: str) -> List[dict]:
query = f"SELECT * FROM users WHERE name LIKE '%{name}%'"
return await db.execute(query)
# GOOD: Using parameterized queries
async def get_users(name: str) -> List[dict]:
query = text("SELECT * FROM users WHERE name LIKE :name")
return await db.execute(query, {"name": f"%{name}%"})
5. API Security Misconfigurations
APIs have become the primary attack surface for applications.
Secure Configuration:
from fastapi import FastAPI, Security
from fastapi.security import APIKeyHeader
app = FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")
@app.on_event("startup")
async def startup():
app.add_middleware(
CORSMiddleware,
allow_origins=["https://trusted-domain.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/api/sensitive-data")
async def get_sensitive_data(api_key: str = Security(api_key_header)):
if not is_valid_api_key(api_key):
raise HTTPException(status_code=403)
return {"data": "sensitive"}
6. Vulnerable and Outdated Components
Supply chain attacks have increased dramatically.
Prevention:
# Example GitHub Actions workflow for dependency scanning
name: Security Scan
on:
push:
branches: [ main ]
schedule:
- cron: '0 0 * * *'
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/python@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
7. Identification and Authentication Failures
Multi-factor authentication bypasses are increasing.
Implementation:
from pyotp import TOTP
from argon2 import PasswordHasher
class AuthService:
def __init__(self):
self.ph = PasswordHasher()
def verify_mfa(self, user: User, token: str) -> bool:
totp = TOTP(user.mfa_secret)
return totp.verify(token)
def hash_password(self, password: str) -> str:
return self.ph.hash(password)
async def authenticate(
self,
email: str,
password: str,
mfa_token: str
) -> User:
user = await get_user_by_email(email)
if not user or not self.ph.verify(user.password_hash, password):
raise InvalidCredentials()
if not self.verify_mfa(user, mfa_token):
raise InvalidMFAToken()
return user
8. Software and Data Integrity Failures
Ensuring the integrity of software updates and data.
Implementation:
import hashlib
from typing import Optional
def verify_file_integrity(
file_path: str,
expected_hash: str
) -> bool:
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest() == expected_hash
def secure_download_and_verify(
url: str,
expected_hash: str
) -> Optional[bytes]:
response = requests.get(url)
if response.status_code != 200:
return None
content = response.content
actual_hash = hashlib.sha256(content).hexdigest()
if actual_hash != expected_hash:
raise SecurityException("File integrity check failed")
return content
9. Security Logging and Monitoring Failures
Proper logging is crucial for detecting and responding to attacks.
Implementation:
import structlog
from datetime import datetime
logger = structlog.get_logger()
class SecurityLogger:
def __init__(self):
self.logger = structlog.get_logger()
def log_security_event(
self,
event_type: str,
user_id: str,
ip_address: str,
details: dict
):
self.logger.info(
"security_event",
event_type=event_type,
user_id=user_id,
ip_address=ip_address,
timestamp=datetime.utcnow().isoformat(),
**details
)
def log_failed_login(self, user_id: str, ip_address: str):
self.log_security_event(
"failed_login",
user_id,
ip_address,
{"attempt_time": datetime.utcnow().isoformat()}
)
10. Server-Side Request Forgery (SSRF)
SSRF attacks continue to be a significant threat.
Prevention:
from urllib.parse import urlparse
import ipaddress
def is_safe_url(url: str) -> bool:
parsed = urlparse(url)
try:
ip = ipaddress.ip_address(parsed.hostname)
return not (
ip.is_private or
ip.is_loopback or
ip.is_link_local or
ip.is_multicast
)
except ValueError:
return parsed.hostname not in [
'localhost',
'127.0.0.1',
'::1'
]
async def fetch_external_resource(url: str) -> bytes:
if not is_safe_url(url):
raise SecurityException("Invalid URL")
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.read()
Conclusion
The OWASP Top 10 2025 reflects the evolving threat landscape, particularly with the rise of AI-powered applications. Key takeaways:
- Implement strong access controls
- Protect AI/ML models from injection attacks
- Use modern cryptography properly
- Validate all inputs
- Monitor and log security events
- Keep dependencies updated
- Implement proper authentication
- Verify software integrity
- Prevent SSRF attacks
Stay vigilant and keep your security practices up to date with the evolving threat landscape.