Python Requests Session HTTP in Context Manager Vulnerability

Medium Risk Insecure Transport
PythonRequestsHTTPInsecure TransportSessionContext ManagerEncryption

What it is

Application uses HTTP (unencrypted) connections within a requests session context manager, exposing data transmission to eavesdropping and man-in-the-middle attacks.

import requests @app.route('/fetch_api_data') def fetch_api_data(): # Vulnerable: HTTP session in context manager with requests.Session() as session: # Insecure: HTTP connection exposes data response = session.get('http://api.example.com/data') return response.json() @app.route('/submit_form') def submit_form(): # Vulnerable: HTTP POST with sensitive data form_data = request.get_json() with requests.Session() as session: # Dangerous: Sending credentials over HTTP response = session.post( 'http://api.backend.com/auth', json={'username': form_data['user'], 'password': form_data['pass']} ) return {'status': response.status_code} @app.route('/proxy_request') def proxy_request(): # Vulnerable: Multiple HTTP calls in session target_url = request.args.get('url') with requests.Session() as session: # No validation - allows HTTP connections response = session.get(target_url) return response.text
import requests from urllib.parse import urlparse # Secure session configuration def create_secure_session(): session = requests.Session() # Enforce SSL/TLS verification session.verify = True # Set secure headers session.headers.update({ 'User-Agent': 'SecureApp/1.0', 'Accept': 'application/json' }) return session def validate_https_url(url): """Validate that URL uses HTTPS scheme.""" parsed = urlparse(url) if parsed.scheme != 'https': raise ValueError('Only HTTPS URLs are allowed') return url @app.route('/fetch_api_data') def fetch_api_data(): # Secure: HTTPS session with proper configuration with create_secure_session() as session: try: # Secure: HTTPS connection api_url = 'https://api.example.com/data' validate_https_url(api_url) response = session.get( api_url, timeout=10, verify=True # Ensure certificate validation ) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: return {'error': f'API request failed: {str(e)}'}, 500 @app.route('/submit_form') def submit_form(): # Secure: HTTPS POST with proper validation form_data = request.get_json() # Validate required fields if not form_data or 'user' not in form_data or 'pass' not in form_data: return {'error': 'Missing credentials'}, 400 with create_secure_session() as session: try: # Secure: HTTPS endpoint auth_url = 'https://api.backend.com/auth' validate_https_url(auth_url) response = session.post( auth_url, json={ 'username': form_data['user'][:50], # Limit length 'password': form_data['pass'][:100] }, timeout=15, verify=True ) response.raise_for_status() return {'status': 'success', 'code': response.status_code} except requests.exceptions.RequestException as e: return {'error': f'Authentication failed: {str(e)}'}, 500 @app.route('/proxy_request') def proxy_request(): # Secure: URL validation and HTTPS enforcement target_url = request.args.get('url', '') # Validate URL format and scheme try: validate_https_url(target_url) except ValueError as e: return {'error': str(e)}, 400 # Allowlist of permitted domains allowed_domains = ['api.trusted.com', 'secure.partner.com'] parsed_url = urlparse(target_url) if parsed_url.netloc not in allowed_domains: return {'error': 'Domain not allowed'}, 400 with create_secure_session() as session: try: response = session.get( target_url, timeout=10, verify=True, allow_redirects=False # Prevent redirect attacks ) response.raise_for_status() # Return sanitized response return { 'status_code': response.status_code, 'content_type': response.headers.get('content-type', ''), 'data': response.text[:1000] # Limit response size } except requests.exceptions.RequestException as e: return {'error': f'Request failed: {str(e)}'}, 500 # Additional secure configuration class SecureHTTPAdapter(requests.adapters.HTTPAdapter): """Custom adapter that enforces HTTPS.""" def send(self, request, **kwargs): if request.url.startswith('http://'): raise requests.exceptions.InvalidURL('HTTP connections not allowed') return super().send(request, **kwargs) # Example of using the secure adapter @app.route('/ultra_secure_request') def ultra_secure_request(): with requests.Session() as session: # Mount secure adapter that blocks HTTP session.mount('http://', SecureHTTPAdapter()) session.mount('https://', SecureHTTPAdapter()) try: response = session.get('https://api.example.com/secure-data') return response.json() except requests.exceptions.InvalidURL as e: return {'error': 'Insecure connection blocked'}, 400

💡 Why This Fix Works

See fix suggestions for detailed explanation.

Why it happens

Code creates sessions with HTTP: with requests.Session() as s: s.get('http://api.example.com'). HTTP transmits data unencrypted. Credentials, tokens, sensitive data exposed to network eavesdropping. Man-in-the-middle attacks intercept or modify data. Session objects with HTTP connections vulnerable throughout session lifetime.

Root causes

Using HTTP URLs in requests.Session() Context Managers

Code creates sessions with HTTP: with requests.Session() as s: s.get('http://api.example.com'). HTTP transmits data unencrypted. Credentials, tokens, sensitive data exposed to network eavesdropping. Man-in-the-middle attacks intercept or modify data. Session objects with HTTP connections vulnerable throughout session lifetime.

Not Enforcing HTTPS for API Endpoints in Session Configuration

Session configuration allows HTTP: session = requests.Session(); session.get(url) where url from user or config may be HTTP. No protocol validation. Applications should enforce HTTPS for all external communications. Relying on URL correctness without verification enables insecure connections.

Using Environment Variables or Configuration with HTTP URLs

URLs from config containing HTTP: API_URL = os.environ['API_ENDPOINT']; session.get(API_URL). Configuration mistakes or legacy values use HTTP. Environment variables not validated for HTTPS. External configuration sources may contain insecure protocols. Validation required for all URL sources.

Session Reuse Across Both HTTP and HTTPS Connections

Mixing protocols in same session: session.get('https://secure.com'); session.get('http://insecure.com'). Session cookies or headers sent to HTTP after HTTPS. Secure data leaked to insecure connections. Session state should be isolated by protocol. Mixed protocol usage creates security boundary violations.

Development or Debug Code Using HTTP Left in Production

Debug endpoints with HTTP: if DEBUG: url = 'http://localhost'; else: url = 'https://api.com'. Development defaults using HTTP. Debug flags failing in production exposes insecure connections. HTTP should never be in production code, even conditionally. Development configurations must not leak into production.

Fixes

1

Always Use HTTPS URLs, Never HTTP for External Connections

Enforce HTTPS everywhere: session.get('https://api.example.com'). Replace all http:// with https://. For external APIs, HTTPS mandatory. Use url.startswith('https://') validation. Reject HTTP URLs. HTTPS provides encryption, authentication, and integrity for all communications.

2

Validate URL Schemes Before Making Session Requests

Check protocol before requests: from urllib.parse import urlparse; if urlparse(url).scheme != 'https': raise ValueError('HTTPS required'). Validate all URLs from config, environment, or user input. Reject non-HTTPS schemes. Fail fast on protocol violations before establishing connections.

3

Configure Session with Base URL Enforcing HTTPS

Use session adapters with HTTPS base: from requests.adapters import HTTPAdapter; session.mount('https://', HTTPAdapter()). Base URLs with HTTPS prefix. Use libraries like requests-toolbelt for URL prefixing. Mount adapters only for HTTPS scheme. Prevent HTTP through session configuration.

4

Use Environment Variables with Validation and Default HTTPS

Validate environment URLs: API_URL = os.environ.get('API_URL', 'https://api.example.com'); assert API_URL.startswith('https://'), 'HTTPS required'. Provide HTTPS defaults. Validate during application startup. Use schema validation for configuration files ensuring all URLs use HTTPS protocol.

5

Implement Certificate Validation and Security Headers

Enable verification: session.get(url, verify=True). Never set verify=False. Use cert pinning for critical APIs: session.get(url, verify='/path/to/certfile.pem'). Add security headers. Configure TLS version minimums: from requests.adapters import HTTPAdapter; session.mount('https://', HTTPAdapter(max_retries=3)).

6

Use Static Analysis to Detect HTTP URL Usage

Scan for HTTP URLs: grep -r "http://" --include="*.py" or use bandit with custom rules. Fail CI/CD on HTTP URL detection. Use pre-commit hooks checking for insecure protocols. Regular security audits for URL schemes. Automated detection prevents HTTP from entering codebase.

Detect This Vulnerability in Your Code

Sourcery automatically identifies python requests session http in context manager vulnerability and many other security issues in your codebase.