{"title":"Insecure Direct Object Reference (IDOR) via JWT Sub Claim Manipulation","language":"Python","severity":"Critical","cwe":"CWE-639","source_lines":[6],"flow_lines":[5,6,7,8],"sink_lines":[8],"vulnerable_code":"import jwt\nfrom flask import request, jsonify\nfrom db import fetch_medical_record\ndef get_patient_record():\n    bearer = request.headers.get('Authorization', '').split(' ')[1]\n    payload = jwt.decode(bearer, options={\"verify_signature\": False})\n    pid = payload.get('sub')\n    rec = fetch_medical_record(pid)\n    if rec is None:\n        return jsonify({'error': 'not found'}), 404\n    return jsonify(rec), 200","explanation":"The JWT token is decoded with 'verify_signature': False, meaning the server accepts any JWT without validating its cryptographic signature. An attacker can forge a JWT with an arbitrary 'sub' claim (any patient's ID) and the server will blindly trust it, passing the attacker-controlled 'pid' directly to fetch_medical_record() — a classic IDOR vulnerability enabling unauthorized access to other patients' medical records.","remediation":"The fix enforces full JWT signature verification using a server-side secret key and a specified algorithm, so forged or tampered tokens are rejected. Additionally, an explicit authorization check is added so that even with a valid token, a user can only access their own medical record unless they hold a privileged role (e.g., doctor or admin), eliminating the IDOR vulnerability. Proper error handling for expired and invalid tokens is also included.","secure_code":"import jwt\nfrom flask import request, jsonify\nfrom db import fetch_medical_record\nfrom config import JWT_SECRET_KEY, JWT_ALGORITHM\n\ndef get_patient_record():\n    auth_header = request.headers.get('Authorization', '')\n    if not auth_header.startswith('Bearer '):\n        return jsonify({'error': 'missing or malformed authorization header'}), 401\n    token = auth_header.split(' ', 1)[1]\n\n    try:\n        payload = jwt.decode(\n            token,\n            JWT_SECRET_KEY,\n            algorithms=[JWT_ALGORITHM],\n            options={\"verify_signature\": True}\n        )\n    except jwt.ExpiredSignatureError:\n        return jsonify({'error': 'token expired'}), 401\n    except jwt.InvalidTokenError:\n        return jsonify({'error': 'invalid token'}), 401\n\n    authenticated_user_id = payload.get('sub')\n    if not authenticated_user_id:\n        return jsonify({'error': 'invalid token claims'}), 401\n\n    requested_pid = request.args.get('patient_id', authenticated_user_id)\n\n    user_role = payload.get('role', 'patient')\n    if requested_pid != authenticated_user_id and user_role not in ('doctor', 'admin'):\n        return jsonify({'error': 'access denied'}), 403\n\n    rec = fetch_medical_record(requested_pid)\n    if rec is None:\n        return jsonify({'error': 'not found'}), 404\n    return jsonify(rec), 200"}