Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:00:42 +08:00
commit cc49e355bc
37 changed files with 10917 additions and 0 deletions

View File

@@ -0,0 +1,219 @@
---
name: Reviewing Authentication and Authorization Security
description: Use when reviewing authentication or authorization code. Provides comprehensive security guidance on JWT validation, token exchange, OAuth 2.0/2.1 compliance, PKCE, Resource Indicators, MCP authorization, session management, and API authentication. Covers critical vulnerabilities including token forwarding, audience validation, algorithm confusion, confused deputy attacks, and authentication bypass. Invoke when analyzing any authentication, authorization, or access control code changes.
---
# Authentication and Authorization Security Review
This skill provides comprehensive security guidance for reviewing authentication and authorization code, with deep expertise in JWT tokens and MCP (Model Context Protocol) servers.
## When to Use This Skill
Invoke this skill when reviewing:
- JWT authentication or authorization implementation
- OAuth 2.0/2.1 flows and token handling
- Service-to-service authentication patterns
- MCP server implementations
- Code that forwards, exchanges, or validates tokens
- Authorization middleware or security filters
- API authentication endpoints
- Session management and cookie-based authentication
- API key or bearer token authentication
- Role-based access control (RBAC) or permission systems
- Multi-factor authentication (MFA) flows
## Key Security Areas
### 1. JWT Token Security
For comprehensive JWT security guidance, see `reference/jwt-security.md`. Key areas:
**Critical Vulnerabilities:**
- **Token Forwarding**: Never forward JWTs to services not in their audience claim
- **Audience Validation**: Every service MUST validate the `aud` claim
- **Algorithm Confusion**: Explicit algorithm enforcement (no `none`, no user-controlled)
- **Signature Validation**: All tokens must be cryptographically verified
**Severity Levels:**
- CRITICAL: Token forwarding, missing signature validation, algorithm confusion
- HIGH: Missing audience/issuer validation, token exchange not used
- MEDIUM: Weak secrets, overly broad scopes, insecure storage
**Correct Pattern - Token Exchange:**
When Service A needs to call Service B on behalf of a user:
1. Service A validates user's token
2. Service A exchanges token for Service B-specific token (RFC 8693)
3. Service A calls Service B with the exchanged token
4. Service B validates the token has correct audience claim
**Review Checklist:**
- [ ] Audience validation for all services
- [ ] Explicit algorithm enforcement
- [ ] Signature validation present
- [ ] Token exchange used (not forwarding)
- [ ] Issuer validation against trusted sources
- [ ] Expiration and other claim validation
- [ ] Secure token storage (not in URLs or localStorage for sensitive data)
### 2. MCP Server Security
For comprehensive MCP authorization guidance, see `reference/mcp-authorization.md`. Key areas:
**MCP Specification Requirements (June 2025):**
- **OAuth 2.1**: MUST use OAuth 2.1 (not 2.0)
- **PKCE**: Mandatory for all authorization flows
- **Resource Indicators (RFC 8707)**: Mandatory for explicit audience targeting
- **Audience Validation**: MCP servers MUST validate tokens are issued for them
- **No Sessions**: MUST NOT use session-based authentication for MCP operations
**Critical MCP Vulnerability - Token Forwarding:**
The most common and critical MCP security issue is forwarding user tokens from inference servers to MCP servers.
```
❌ INSECURE:
User → Inference Server (user JWT) → MCP Server (forwarded user JWT)
Problem: MCP server accepts token not issued for it (confused deputy attack)
✅ SECURE:
User → Inference Server (user JWT) → Auth Server (token exchange)
→ MCP Server (MCP-specific JWT)
Benefit: MCP token has correct audience claim and downscoped permissions
```
**Review Checklist:**
- [ ] OAuth 2.1 implementation (not 2.0)
- [ ] PKCE with S256 method in all flows
- [ ] Resource Indicators in token requests
- [ ] Audience validation matches MCP server identifier
- [ ] Token exchange for upstream service calls
- [ ] Scope validation with insufficient_scope responses
- [ ] No session-based authentication for MCP operations
- [ ] HTTPS/TLS for all communication
- [ ] Input validation for tool parameters (prompt injection protection)
### 3. Common Security Anti-Patterns
**Token Forwarding (CRITICAL):**
```python
# ❌ CRITICAL ISSUE
def call_api(user_token):
response = requests.get(
"https://other-service/api",
headers={"Authorization": f"Bearer {user_token}"}
)
```
**Missing Audience Validation (CRITICAL):**
```python
# ❌ VULNERABLE
decoded = jwt.decode(token, public_key, algorithms=['RS256'])
# Missing audience validation!
# ✅ SECURE
decoded = jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience='https://api.myservice.com',
issuer='https://auth.example.com'
)
```
**Algorithm Confusion (CRITICAL):**
```python
# ❌ VULNERABLE
header = jwt.get_unverified_header(token)
decoded = jwt.decode(token, key, algorithms=[header['alg']])
# ✅ SECURE
decoded = jwt.decode(token, public_key, algorithms=['RS256'])
```
## Review Workflow
### 1. Identify Security-Sensitive Code
Scan for:
- JWT encoding/decoding operations
- OAuth flow implementations
- Token forwarding between services
- MCP server endpoints
- Authorization middleware
- API authentication handlers
### 2. Apply Appropriate Checklist
Use the checklists from:
- `reference/jwt-security.md` for JWT-related code
- `reference/mcp-authorization.md` for MCP server code
### 3. Categorize Findings
Follow the severity guide from the pr-review skill:
- **CRITICAL**: Security vulnerabilities, must block merge
- **HIGH**: Significant security issues, should fix before merge
- **MEDIUM**: Security improvements, should address
- **LOW**: Security suggestions, optional
### 4. Provide Specific Guidance
For each finding:
- Identify the specific vulnerability
- Explain why it's a security issue
- Reference the relevant RFC or standard
- Provide concrete code example of the fix
- Include file:line references
## Key RFCs and Standards
### JWT and OAuth
- **RFC 7519**: JSON Web Token (JWT)
- **RFC 8693**: OAuth 2.0 Token Exchange
- **RFC 8707**: Resource Indicators for OAuth 2.0
- **RFC 9068**: JWT Profile for OAuth 2.0 Access Tokens
- **RFC 9700**: OAuth 2.0 Security Best Current Practice (January 2025)
### MCP
- **MCP Authorization Spec** (June 2025): OAuth 2.1 for MCP
- **RFC 7636**: PKCE (mandatory for MCP)
- **OAuth 2.1**: Required authorization framework for MCP
## When to Escalate
Mark as CRITICAL and escalate if you find:
**JWT Issues:**
- Tokens forwarded to services not in their audience
- Missing signature validation
- Algorithm confusion vulnerabilities
- No audience or issuer validation
- Tokens in URLs or logged in full
**MCP Issues:**
- Token forwarding from inference/API servers to MCP servers
- Missing audience validation in MCP server
- No PKCE in authorization flows
- Missing Resource Indicators in token requests
- Session-based authentication for MCP operations
- MCP tools with code execution and no sandboxing
- HTTP (not HTTPS) in production
## Validation
Before completing security review, ensure:
- [ ] All JWT operations reviewed against JWT checklist
- [ ] All MCP operations reviewed against MCP checklist
- [ ] Token flow patterns verified (exchange vs. forwarding)
- [ ] Severity assigned to each finding
- [ ] Specific remediation guidance provided
- [ ] File:line references included
- [ ] RFC/standard references cited
## Reference Documentation
For detailed security guidance:
- **`reference/jwt-security.md`**: Comprehensive JWT security best practices, common vulnerabilities, and code examples
- **`reference/mcp-authorization.md`**: Complete MCP OAuth 2.1 implementation guide, architecture patterns, and security considerations
These references contain detailed examples, vulnerability explanations, and implementation patterns. Consult them when you need deep technical context for security findings.

View File

@@ -0,0 +1,382 @@
# JWT Security Best Practices
This reference provides comprehensive guidance for reviewing JWT (JSON Web Token) implementation and usage in pull requests.
## Critical Security Principles
### 1. Never Forward JWTs to Unintended Services
**The Problem:**
A JWT contains an `aud` (audience) claim that specifies which service(s) the token is intended for. Forwarding a JWT to a service not listed in the audience claim creates serious security vulnerabilities.
**Security Impact:**
- **Confused Deputy Attack**: The receiving service cannot verify that the forwarding service is authorized to act on behalf of the user
- **Privilege Escalation**: If the receiving service accepts tokens not intended for it, attackers can misuse tokens from one service at another
- **ALBEAST-Class Vulnerability**: Tokens intended for one tenant/service can be used at another
**What to Look For in PRs:**
```python
# ❌ CRITICAL SECURITY ISSUE
def call_external_api(user_token):
# Forwarding user's JWT directly to third-party service
response = requests.get(
"https://third-party-api.com/resource",
headers={"Authorization": f"Bearer {user_token}"}
)
```
**Severity:** CRITICAL - Must be blocked before merge
### 2. Validate Audience Claims
Every service that accepts JWTs **MUST** validate the `aud` claim matches its own identifier.
**RFC Requirements:**
- Per RFC 7519: "Each principal intended to process the JWT MUST identify itself with a value in the audience claim"
- Per RFC 9068: "The resource server MUST validate that the aud claim contains a resource indicator value corresponding to an identifier the resource server expects for itself"
- **The JWT MUST be rejected if the audience does not match**
**What to Look For in PRs:**
```python
# ❌ MISSING VALIDATION
def verify_token(token):
decoded = jwt.decode(token, public_key, algorithms=['RS256'])
# Missing audience validation!
return decoded
# ✅ CORRECT VALIDATION
def verify_token(token):
decoded = jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience='https://api.myservice.com' # Validates aud claim
)
return decoded
```
**Severity:** CRITICAL if missing, HIGH if incomplete
### 3. Validate All Critical Claims
Beyond audience, validate:
**Required Validations:**
- `iss` (issuer): Verify the token came from a trusted authorization server
- `aud` (audience): Verify the token is intended for this service
- `exp` (expiration): Reject expired tokens
- `nbf` (not before): Reject tokens used before their valid time
- `alg` (algorithm): Prevent algorithm confusion attacks
**What to Look For in PRs:**
```python
# ❌ VULNERABLE TO ALGORITHM CONFUSION
def verify_token(token):
# Accepts ANY algorithm from the token header
decoded = jwt.decode(token, secret, algorithms=None)
# ✅ CORRECT - EXPLICIT ALGORITHM
def verify_token(token):
# Only accepts expected algorithm
decoded = jwt.decode(
token,
public_key,
algorithms=['RS256'], # Explicit, not from token
issuer='https://auth.example.com',
audience='https://api.example.com'
)
```
**Severity:** CRITICAL for algorithm validation, HIGH for other claims
### 4. Use Token Exchange for Service-to-Service Communication
When a service needs to call another service on behalf of a user, **use OAuth Token Exchange (RFC 8693)** rather than forwarding the original token.
**The Correct Pattern:**
```python
# ✅ SECURE TOKEN EXCHANGE PATTERN
def call_downstream_service(user_token):
# Exchange user token for service-specific token
exchange_response = requests.post(
'https://auth.example.com/token',
data={
'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
'subject_token': user_token,
'subject_token_type': 'urn:ietf:params:oauth:token-type:access_token',
'resource': 'https://downstream-service.example.com',
'scope': 'read:data' # Downscoped to minimum needed
}
)
downstream_token = exchange_response.json()['access_token']
# Use the service-specific token
response = requests.get(
'https://downstream-service.example.com/api/resource',
headers={'Authorization': f'Bearer {downstream_token}'}
)
```
**Benefits of Token Exchange:**
1. **Correct Audience**: New token has proper `aud` claim for downstream service
2. **Least Privilege**: Token is downscoped to minimum permissions needed
3. **Audit Trail**: Clear chain of delegation (user → service A → service B)
4. **Prevents Confused Deputy**: Downstream service can validate the token was properly issued
**What to Look For in PRs:**
- Services forwarding user JWTs to other services without exchange
- Missing token exchange implementation where multi-service calls exist
- Tokens with overly broad scopes being passed between services
**Severity:** CRITICAL in security-sensitive contexts, HIGH otherwise
### 5. Apply Principle of Least Privilege
**Scope Downscoping:**
When exchanging tokens, request only the minimum scopes needed for the specific operation.
```python
# ❌ OVER-PRIVILEGED
exchange_data = {
'scope': 'read write admin delete' # Too many permissions!
}
# ✅ LEAST PRIVILEGE
exchange_data = {
'scope': 'read:invoices' # Only what's needed
}
```
**Severity:** MEDIUM to HIGH depending on the over-privileging
### 6. Secure Token Storage and Transmission
**Transport Security:**
- JWTs MUST be transmitted over HTTPS only
- Never log full JWTs (mask them if needed for debugging)
- Never include JWTs in URLs (query parameters, path segments)
**Storage Security:**
- Don't store JWTs in localStorage if they contain sensitive data (XSS risk)
- Consider httpOnly cookies for web applications
- Use secure, encrypted storage on mobile platforms
- Implement token refresh to minimize long-lived token exposure
**What to Look For in PRs:**
```javascript
// ❌ SECURITY ISSUES
localStorage.setItem('token', jwt); // XSS vulnerability
console.log('Token:', jwt); // Logging sensitive data
const url = `/api/resource?token=${jwt}`; // Token in URL
// ✅ BETTER PRACTICES
// Use httpOnly cookie or secure storage
document.cookie = `token=${jwt}; Secure; HttpOnly; SameSite=Strict`;
console.log('Token:', jwt.substring(0, 10) + '...'); // Masked logging
```
**Severity:** HIGH for URL exposure, MEDIUM for storage issues
## Algorithm Confusion Attacks
### The Vulnerability
JWT headers include an `alg` parameter that specifies the signing algorithm. If the verification code doesn't enforce the expected algorithm, attackers can:
1. Change RS256 (RSA) to HS256 (HMAC)
2. Use the RSA public key as the HMAC secret
3. Create validly-signed tokens
**What to Look For in PRs:**
```python
# ❌ VULNERABLE
def verify_token(token):
# Algorithm taken from token header - DANGEROUS!
header = jwt.get_unverified_header(token)
alg = header['alg']
decoded = jwt.decode(token, key, algorithms=[alg])
# ✅ SECURE
def verify_token(token):
# Algorithm explicitly specified and validated
decoded = jwt.decode(
token,
public_key,
algorithms=['RS256'] # Only RS256 accepted
)
```
**Severity:** CRITICAL
### None Algorithm Attack
Some JWT libraries accept `"alg": "none"` which bypasses signature verification entirely.
**What to Look For in PRs:**
```python
# ❌ VULNERABLE
jwt.decode(token, verify=False) # Dangerous!
jwt.decode(token, algorithms=['RS256', 'none']) # Allows none!
# ✅ SECURE
jwt.decode(token, public_key, algorithms=['RS256'])
```
**Severity:** CRITICAL
## Common JWT Anti-Patterns
### 1. Treating ID Tokens as Access Tokens
**Problem:** ID tokens (from OpenID Connect) are meant for the client that requested authentication, NOT for API authorization.
```python
# ❌ WRONG
# Forwarding ID token to API
api_call(headers={'Authorization': f'Bearer {id_token}'})
# ✅ CORRECT
# Use access token for API calls
api_call(headers={'Authorization': f'Bearer {access_token}'})
```
**Severity:** HIGH
### 2. Missing Signature Validation
**Problem:** Accepting unsigned JWTs or skipping validation.
```python
# ❌ VULNERABLE
payload = jwt.decode(token, options={"verify_signature": False})
# ✅ SECURE
payload = jwt.decode(token, public_key, algorithms=['RS256'])
```
**Severity:** CRITICAL
### 3. Trusting Token Content Without Validation
**Problem:** Extracting claims before validating signature and claims.
```python
# ❌ DANGEROUS
def get_user_id(token):
# Decodes without validation!
payload = jwt.decode(token, options={"verify_signature": False})
return payload['user_id']
# ✅ SAFE
def get_user_id(token):
# Validates first, then extracts
payload = jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience='https://api.example.com',
issuer='https://auth.example.com'
)
return payload['user_id']
```
**Severity:** CRITICAL
### 4. Using Weak Secrets for HS256
**Problem:** Using predictable or weak secrets for HMAC signing.
```python
# ❌ WEAK SECRET
secret = "secret123"
jwt.encode(payload, secret, algorithm='HS256')
# ✅ STRONG SECRET
# Use cryptographically random, high-entropy secret
# At least 256 bits (32 bytes) for HS256
import secrets
secret = secrets.token_bytes(32)
```
**Severity:** CRITICAL
### 5. Overly Broad Audiences
**Problem:** Using wildcard or overly generic audience values.
```python
# ❌ TOO BROAD
token_data = {
'aud': '*', # Accepts anywhere!
'aud': 'https://example.com' # Too generic
}
# ✅ SPECIFIC
token_data = {
'aud': 'https://api.example.com/v1/orders' # Specific service
}
```
**Severity:** MEDIUM to HIGH
## Review Checklist for JWT Code
When reviewing PRs involving JWT authentication/authorization:
### Critical Checks
- [ ] **Audience validation**: Every service validates `aud` claim matches its identifier
- [ ] **Algorithm enforcement**: Explicit algorithm list, no `none`, no user-controlled algorithm
- [ ] **Signature validation**: All tokens are cryptographically validated
- [ ] **Issuer validation**: `iss` claim validated against trusted issuers
- [ ] **No token forwarding**: Tokens are not forwarded to services not in their `aud` claim
### High Priority Checks
- [ ] **Token exchange**: Service-to-service calls use token exchange, not forwarding
- [ ] **Expiration validation**: `exp` claim checked and enforced
- [ ] **Scope downscoping**: Exchanged tokens request minimum necessary scopes
- [ ] **ID token misuse**: ID tokens not used for API authorization
- [ ] **Transport security**: Tokens only transmitted over HTTPS
### Medium Priority Checks
- [ ] **Least privilege**: Scopes are specific and minimal
- [ ] **Secure storage**: Tokens stored securely (not localStorage for sensitive data)
- [ ] **Token refresh**: Short-lived tokens with refresh mechanism
- [ ] **Logging safety**: Tokens not logged in full
- [ ] **Error messages**: Don't leak token information in errors
### Code Pattern Recognition
**Token Forwarding Pattern (Usually Wrong):**
```python
# Server receives user_token from client
# Server forwards user_token to another service
downstream_service.call(authorization=user_token) # ❌ Check this!
```
**Token Exchange Pattern (Usually Correct):**
```python
# Server receives user_token from client
# Server exchanges for service-specific token
new_token = auth_server.exchange_token(user_token, target_service)
# Server uses new token
downstream_service.call(authorization=new_token) # ✅ Good!
```
## Key RFCs and Standards
- **RFC 7519**: JSON Web Token (JWT) - Core standard
- **RFC 8693**: OAuth 2.0 Token Exchange - Service-to-service delegation
- **RFC 8707**: Resource Indicators for OAuth 2.0 - Explicit audience specification
- **RFC 9068**: JWT Profile for OAuth 2.0 Access Tokens - Access token best practices
- **RFC 9700**: OAuth 2.0 Security Best Current Practice (January 2025) - Latest security guidance
## When to Escalate
Escalate to security team or mark as CRITICAL if you find:
- Tokens forwarded to services not in their audience
- Missing signature validation
- Algorithm confusion vulnerabilities (accepting `none` or user-controlled algorithm)
- Tokens containing sensitive data logged or exposed in URLs
- No audience or issuer validation
- Token exchange not used in multi-service architectures

View File

@@ -0,0 +1,571 @@
# MCP (Model Context Protocol) Authorization Security
This reference provides comprehensive guidance for reviewing MCP server implementations with a focus on OAuth 2.1 authorization and security best practices.
## Overview
The Model Context Protocol (MCP) specification finalized OAuth 2.1-based authorization in June 2025. MCP servers represent high-value targets because they:
- Store authentication tokens for multiple services
- Execute actions across connected services
- Can be invoked by AI agents with varying levels of user oversight
- Potentially have access to sensitive data and operations
**Key Security Principle:** MCP servers must implement strict authorization controls to prevent unauthorized access and token misuse.
## MCP Authorization Requirements
### 1. OAuth 2.1 Compliance (MANDATORY)
The MCP specification requires OAuth 2.1 as the authorization foundation.
**Core Requirements:**
- MUST use OAuth 2.1 (not OAuth 2.0)
- MUST implement PKCE (Proof Key for Code Exchange) for all clients
- MUST implement Resource Indicators (RFC 8707)
- MUST validate tokens with correct audience claims
- MUST NOT use sessions for authentication
**What to Look For in PRs:**
```python
# ❌ NON-COMPLIANT - OAuth 2.0 without PKCE
@app.route('/authorize')
def authorize():
redirect_uri = request.args.get('redirect_uri')
# Missing code_challenge and code_challenge_method
auth_code = generate_auth_code()
return redirect(f'{redirect_uri}?code={auth_code}')
# ✅ COMPLIANT - OAuth 2.1 with PKCE
@app.route('/authorize')
def authorize():
code_challenge = request.args.get('code_challenge')
code_challenge_method = request.args.get('code_challenge_method')
if not code_challenge or code_challenge_method != 'S256':
return {'error': 'invalid_request', 'error_description': 'PKCE required'}, 400
auth_code = generate_auth_code(code_challenge)
return redirect(f'{redirect_uri}?code={auth_code}')
```
**Severity:** CRITICAL if PKCE missing, HIGH if OAuth 2.0 instead of 2.1
### 2. Resource Indicators (RFC 8707) - MANDATORY
MCP clients MUST implement Resource Indicators to explicitly specify the target MCP server.
**Purpose:**
- Ensures tokens are audience-restricted to specific MCP servers
- Prevents token misuse across different MCP servers
- Enables proper multi-tenant security
**What to Look For in PRs:**
```python
# ❌ MISSING RESOURCE INDICATOR
token_request = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': redirect_uri,
# Missing 'resource' parameter!
}
# ✅ CORRECT - WITH RESOURCE INDICATOR
token_request = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': redirect_uri,
'resource': 'https://mcp-server.example.com', # Explicit target
'code_verifier': code_verifier # PKCE
}
```
**Audience Validation:**
```python
# ✅ MCP SERVER MUST VALIDATE AUDIENCE
def validate_token(token):
try:
payload = jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience='https://mcp-server.example.com', # Must match resource
issuer='https://auth.example.com'
)
return payload
except jwt.InvalidAudienceError:
raise HTTPException(403, 'Token not intended for this MCP server')
```
**Severity:** CRITICAL if missing
### 3. Strict Token Acceptance Policy
**MCP servers MUST NOT accept tokens that were not explicitly issued for them.**
This is the core defense against confused deputy attacks.
**What to Look For in PRs:**
```python
# ❌ VULNERABLE - ACCEPTS ANY TOKEN
def authorize_request(request):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
# No audience validation!
payload = jwt.decode(token, public_key, algorithms=['RS256'])
return payload['user_id']
# ✅ SECURE - VALIDATES AUDIENCE
def authorize_request(request):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
try:
payload = jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience=MCP_SERVER_IDENTIFIER, # This server's identifier
issuer=TRUSTED_ISSUER
)
except jwt.InvalidAudienceError:
raise Forbidden('Token not issued for this MCP server')
return payload
```
**Severity:** CRITICAL
### 4. Scope Validation and Insufficient Scope Response
MCP servers MUST validate that tokens have the required scopes for operations.
**Required Behavior:**
- When a token has insufficient scope, respond with HTTP 403 Forbidden
- Include `WWW-Authenticate` header with `error="insufficient_scope"`
- Optionally include `scope` parameter indicating required scopes
**What to Look For in PRs:**
```python
# ❌ MISSING SCOPE VALIDATION
@app.route('/tools/invoke', methods=['POST'])
def invoke_tool(token_payload):
# No scope check!
result = execute_tool(request.json['tool_name'])
return result
# ✅ CORRECT SCOPE VALIDATION
@app.route('/tools/invoke', methods=['POST'])
def invoke_tool(token_payload):
required_scope = 'tools.invoke'
if required_scope not in token_payload.get('scope', '').split():
response = Response(
'Insufficient scope',
status=403,
headers={
'WWW-Authenticate': f'Bearer error="insufficient_scope", scope="{required_scope}"'
}
)
return response
result = execute_tool(request.json['tool_name'])
return result
```
**Severity:** HIGH
### 5. No Session-Based Authentication
**MCP servers MUST NOT use sessions for authentication.**
This is a specific requirement of the MCP specification.
**What to Look For in PRs:**
```python
# ❌ VIOLATES MCP SPEC - USING SESSIONS
@app.route('/tools/list')
def list_tools():
if 'user_id' not in session:
return {'error': 'unauthorized'}, 401
# Using Flask session - NOT ALLOWED
# ✅ COMPLIANT - TOKEN-BASED
@app.route('/tools/list')
def list_tools():
token = request.headers.get('Authorization', '').replace('Bearer ', '')
payload = validate_mcp_token(token) # OAuth 2.1 token validation
return get_tools_for_user(payload['sub'])
```
**Severity:** CRITICAL - violates MCP specification
### 6. Secure Session ID Generation (if used for OAuth flow)
If the MCP server or authorization server uses session IDs during the OAuth flow (not for authentication):
**Requirements:**
- MUST use secure, non-deterministic session IDs
- MUST use cryptographically secure random number generators
- MUST have sufficient entropy to prevent guessing
**What to Look For in PRs:**
```python
# ❌ WEAK SESSION ID
import random
session_id = str(random.randint(1000, 9999)) # Predictable!
# ✅ SECURE SESSION ID
import secrets
session_id = secrets.token_urlsafe(32) # Cryptographically secure
```
**Severity:** HIGH
## Token Forwarding to MCP Servers
### The Critical Security Issue
A common anti-pattern is forwarding user authentication tokens from an inference server (or other service) to an MCP server.
**Example of Vulnerable Flow:**
```
User → Inference Server (with user JWT)
Inference Server → MCP Server (forwarding user JWT) ❌ INSECURE
```
**Why This Is Dangerous:**
1. **Audience Mismatch**: User JWT has `aud` claim for inference server, not MCP server
2. **Confused Deputy**: MCP server cannot verify inference server is authorized to delegate
3. **No Scope Restriction**: MCP server receives user's full permissions, not downscoped
4. **Violates MCP Spec**: MCP servers must only accept tokens issued for them
**What to Look For in PRs:**
```python
# ❌ CRITICAL VULNERABILITY
class InferenceServer:
def call_mcp_tool(self, user_token, tool_name, params):
# Forwarding user token directly to MCP server!
response = requests.post(
f'{MCP_SERVER_URL}/tools/invoke',
headers={'Authorization': f'Bearer {user_token}'}, # WRONG!
json={'tool': tool_name, 'params': params}
)
return response.json()
```
**Severity:** CRITICAL - Must be blocked before merge
### The Correct Pattern: Token Exchange
**Secure Flow:**
```
User → Inference Server (with user JWT)
↓ (validate user JWT)
Inference Server → Auth Server (token exchange request)
↓ (receives MCP-scoped token)
Inference Server → MCP Server (with MCP-specific token) ✓ SECURE
```
**What to Look For in PRs:**
```python
# ✅ CORRECT - TOKEN EXCHANGE
class InferenceServer:
def call_mcp_tool(self, user_token, tool_name, params):
# Step 1: Validate user token
user_claims = self.validate_user_token(user_token)
# Step 2: Exchange for MCP-specific token
mcp_token = self.exchange_token_for_mcp(
user_token=user_token,
mcp_server='https://mcp-server.example.com',
required_scopes=['tools.invoke']
)
# Step 3: Use MCP-specific token
response = requests.post(
f'{MCP_SERVER_URL}/tools/invoke',
headers={'Authorization': f'Bearer {mcp_token}'}, # Correct audience
json={'tool': tool_name, 'params': params}
)
return response.json()
def exchange_token_for_mcp(self, user_token, mcp_server, required_scopes):
"""Exchange user token for MCP-server-specific token"""
exchange_response = requests.post(
f'{AUTH_SERVER_URL}/token',
data={
'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
'subject_token': user_token,
'subject_token_type': 'urn:ietf:params:oauth:token-type:access_token',
'resource': mcp_server, # RFC 8707 Resource Indicator
'scope': ' '.join(required_scopes) # Downscoped
}
)
if exchange_response.status_code != 200:
raise AuthorizationError('Token exchange failed')
return exchange_response.json()['access_token']
```
**Key Security Benefits:**
1. ✅ MCP token has correct `aud` claim for the MCP server
2. ✅ Token is downscoped to minimum needed permissions
3. ✅ Clear audit trail preserved (user → inference → MCP)
4. ✅ Complies with MCP OAuth 2.1 specification
5. ✅ Prevents confused deputy attacks
6. ✅ MCP server can properly validate the token
**Severity:** Implementation of token exchange is CRITICAL when missing
## MCP Server Architecture Patterns
### Pattern 1: Embedded Authorization Server
The MCP server includes its own auth system.
**Characteristics:**
- Handles login, user sessions, consent UI
- Issues and verifies tokens
- Acts as both authorization server and resource server
**Security Considerations:**
- Must implement full OAuth 2.1 spec
- Requires secure user credential management
- Needs proper consent UI for user authorization
- Session management during OAuth flow (not for MCP operations)
### Pattern 2: External Authorization Server (Recommended)
The MCP server delegates OAuth to a trusted external provider.
**Characteristics:**
- Authorization server handles authentication, user management, consent
- MCP server only validates tokens and enforces scopes
- Clear separation of concerns
**Security Benefits:**
- Leverages battle-tested auth infrastructure
- Reduces attack surface of MCP server
- Easier to audit and maintain
- Better compliance with OAuth 2.1 spec
**What to Look For in PRs:**
```python
# ✅ EXTERNAL AUTH SERVER PATTERN
class MCPServer:
def __init__(self, auth_server_url, mcp_server_id):
self.auth_server_url = auth_server_url
self.mcp_server_id = mcp_server_id
# Fetch public keys from auth server
self.public_keys = self.fetch_jwks()
def validate_token(self, token):
"""Validate token issued by external auth server"""
try:
payload = jwt.decode(
token,
self.public_keys,
algorithms=['RS256'],
audience=self.mcp_server_id,
issuer=self.auth_server_url
)
return payload
except jwt.InvalidTokenError as e:
raise Unauthorized(str(e))
def fetch_jwks(self):
"""Fetch JSON Web Key Set from auth server"""
response = requests.get(f'{self.auth_server_url}/.well-known/jwks.json')
return response.json()
```
## Transport Security
### Mutual TLS (mTLS)
For production MCP deployments, especially in enterprise environments:
**Requirement:** Transport security SHOULD use mutual TLS (mTLS) for bidirectional verification.
**What to Look For in PRs:**
```python
# ✅ mTLS CONFIGURATION
import ssl
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.verify_mode = ssl.CERT_REQUIRED
context.load_cert_chain(certfile='server.crt', keyfile='server.key')
context.load_verify_locations(cafile='client_ca.crt')
# Use context in server configuration
server = HTTPServer(('localhost', 8443), MCPRequestHandler)
server.socket = context.wrap_socket(server.socket, server_side=True)
```
**Severity:** MEDIUM for internal deployments, HIGH for external-facing servers
### HTTPS Mandatory
**All MCP communication MUST occur over HTTPS (or equivalent secure transport).**
**What to Look For in PRs:**
- HTTP URLs in production configurations (red flag)
- Missing TLS/SSL certificate validation
- Disabled certificate verification (`verify=False`)
**Severity:** CRITICAL if HTTP used in production
## Security Risks Specific to MCP
### 1. High-Value Target
MCP servers store tokens for multiple services. If compromised:
- Attacker gains access to all connected service tokens
- Can execute actions across all integrated services
- Potential for lateral movement across services
**Mitigation:**
- Encrypt tokens at rest
- Use short-lived tokens with refresh
- Implement rate limiting and anomaly detection
- Audit all token usage
### 2. Prompt Injection Attacks
AI agents can be manipulated through prompt injection to:
- Execute unintended MCP tool invocations
- Access unauthorized resources
- Exfiltrate data through tool responses
**What to Look For in PRs:**
- Input validation on tool parameters
- Scope restrictions preventing dangerous operations
- Audit logging of all tool invocations
- User confirmation for sensitive operations
**Severity:** HIGH to CRITICAL depending on MCP server capabilities
### 3. Cross-Prompt Injection
Malicious content embedded in documents or UI can override agent instructions.
**Mitigation:**
- Sanitize external content before processing
- Implement content security policies
- Separate user instructions from external content
- Require explicit user confirmation for sensitive actions
**Severity:** HIGH
### 4. Remote Code Execution Risk
If MCP tools can execute code or system commands, prompt injection could lead to RCE.
**What to Look For in PRs:**
- Code execution capabilities without sandboxing
- System command execution from tool parameters
- File system access without path validation
- Network access without destination whitelisting
**Severity:** CRITICAL
## Review Checklist for MCP Code
When reviewing PRs involving MCP server implementation:
### Critical Checks
- [ ] **OAuth 2.1 compliance**: Using OAuth 2.1 (not 2.0)
- [ ] **PKCE mandatory**: All authorization flows use PKCE with S256
- [ ] **Resource Indicators**: Token requests include explicit `resource` parameter
- [ ] **Audience validation**: Server validates `aud` claim matches its identifier
- [ ] **No token forwarding**: Server doesn't accept tokens issued for other services
- [ ] **Token exchange**: Uses token exchange for upstream service calls
- [ ] **No session auth**: Doesn't use sessions for MCP operation authentication
### High Priority Checks
- [ ] **Scope validation**: Validates required scopes and returns proper insufficient_scope errors
- [ ] **Issuer validation**: Validates `iss` claim against trusted issuers
- [ ] **Algorithm enforcement**: Explicit algorithm list (no `none`, no user-controlled)
- [ ] **Signature validation**: All tokens cryptographically validated
- [ ] **HTTPS/TLS**: All communication over secure transport
- [ ] **Input validation**: Tool parameters validated and sanitized
### Medium Priority Checks
- [ ] **Token storage**: Tokens encrypted at rest
- [ ] **Audit logging**: Tool invocations logged with user context
- [ ] **Rate limiting**: Prevents abuse of MCP endpoints
- [ ] **Least privilege**: Scopes are minimal and specific
- [ ] **mTLS consideration**: mTLS for production deployments
- [ ] **Secure session IDs**: If used in OAuth flow, cryptographically random
### MCP-Specific Security Patterns
**Inference Server + MCP Architecture:**
```
✅ SECURE PATTERN:
1. User authenticates to inference server
2. Inference server validates user token
3. Inference server exchanges token for MCP-specific token
4. Inference server invokes MCP with proper token
5. MCP server validates audience matches its identifier
❌ INSECURE PATTERN:
1. User authenticates to inference server
2. Inference server forwards user token to MCP
3. MCP server accepts token not issued for it
```
## Platform-Specific Considerations
### Windows 11 MCP Proxy
Windows 11 provides centralized MCP proxy for security:
**Features:**
- Proxy-mediated communication for all MCP interactions
- Centralized policy enforcement
- Consistent authentication and authorization
- Enhanced audit and monitoring
**What to Look For in PRs:**
- Windows platform should integrate with Windows 11 MCP proxy
- Proxy configuration and policy settings
- Proper certificate validation for proxy communication
**Severity:** MEDIUM for Windows deployments
## Key Standards and Specifications
- **MCP Authorization Spec** (June 2025): Official OAuth 2.1 authorization for MCP
- **OAuth 2.1**: Required authorization framework
- **RFC 7636**: PKCE - Mandatory for all MCP clients
- **RFC 8707**: Resource Indicators - Mandatory for MCP token requests
- **RFC 8693**: Token Exchange - Recommended for service-to-service delegation
- **RFC 9068**: JWT Profile for OAuth 2.0 Access Tokens
- **RFC 9700**: OAuth 2.0 Security Best Current Practice (January 2025)
## When to Escalate
Escalate to security team or mark as CRITICAL if you find:
1. **Token forwarding**: Inference/API servers forwarding user tokens to MCP servers
2. **Missing audience validation**: MCP server accepts tokens without validating `aud` claim
3. **No PKCE**: Authorization flow missing PKCE implementation
4. **No Resource Indicators**: Token requests missing `resource` parameter
5. **Session-based auth**: Using sessions for MCP operation authentication
6. **Prompt injection risks**: MCP tools with code execution and no sandboxing
7. **Missing OAuth 2.1**: Still using OAuth 2.0 instead of 2.1
8. **HTTP communication**: Production MCP server using HTTP instead of HTTPS
## Summary
MCP authorization security requires:
1. **OAuth 2.1** with PKCE (mandatory)
2. **Resource Indicators** (RFC 8707) for explicit audience targeting
3. **Strict token validation** (audience, issuer, signature, scopes)
4. **Token exchange** for service-to-service delegation (not forwarding)
5. **No session-based authentication** for MCP operations
6. **Secure transport** (HTTPS/TLS, preferably mTLS)
7. **Input validation** and prompt injection protection
The most common vulnerability is token forwarding from inference servers to MCP servers. This must be replaced with proper token exchange flows.