Authorization and access control security guidance based on Project CodeGuard — covers RBAC/ABAC/ReBAC, IDOR prevention, mass assignment, and transaction authorization
87
82%
Does it follow best practices?
Impact
93%
1.45xAverage score across 6 eval scenarios
Passed
No findings from the security scan
A B2B analytics platform lets workspace members generate and download reports on their projects. The backend team has recently expanded from two roles (admin, member) to four (admin, manager, analyst, viewer), and permissions are now scattered inconsistently across route handlers. During a recent pen test, the testers found that several denied requests left no trace in the logs, making it impossible to detect whether someone was probing for unauthorized resources.
The team lead wants the codebase cleaned up before the next SOC 2 audit: all authorization checks should be enforced consistently, and every time a request is blocked the system must produce a structured record that the security team can use to investigate incidents. The record needs enough detail to reconstruct what happened, but must not expose sensitive personal data that would complicate GDPR compliance.
Produce reports_api.py containing the production-ready Flask application. You should also produce security_notes.md explaining the authorization design and logging approach.
The following files are provided as inputs. Extract them before beginning.
=============== FILE: inputs/reports_api.py =============== from flask import Flask, jsonify, request, abort, g
app = Flask(name)
def get_current_user(): return { "user_id": request.headers.get("X-User-Id", "u-unknown"), "email": request.headers.get("X-User-Email", "user@example.com"), "role": request.headers.get("X-Role", "viewer"), "workspace_id": request.headers.get("X-Workspace-Id", "ws-1"), }
_reports = { "rpt-001": {"id": "rpt-001", "workspace_id": "ws-1", "title": "Q1 Revenue", "owner_id": "u-001"}, "rpt-002": {"id": "rpt-002", "workspace_id": "ws-2", "title": "Churn Analysis", "owner_id": "u-002"}, "rpt-003": {"id": "rpt-003", "workspace_id": "ws-1", "title": "User Growth", "owner_id": "u-003"}, }
ROLE_PERMISSIONS = { "admin": ["reports:list", "reports:read", "reports:create", "reports:delete", "reports:download"], "manager": ["reports:list", "reports:read", "reports:create", "reports:download"], "analyst": ["reports:list", "reports:read", "reports:create"], "viewer": ["reports:list", "reports:read"], }
@app.route("/api/reports", methods=["GET"]) def list_reports(): user = get_current_user() if "reports:list" not in ROLE_PERMISSIONS.get(user["role"], []): abort(403) workspace_reports = [r for r in _reports.values() if r["workspace_id"] == user["workspace_id"]] return jsonify(workspace_reports)
@app.route("/api/reports/<report_id>", methods=["GET"]) def get_report(report_id): user = get_current_user() report = _reports.get(report_id) if report is None: abort(404) return jsonify(report)
@app.route("/api/reports", methods=["POST"]) def create_report(): user = get_current_user() if "reports:create" not in ROLE_PERMISSIONS.get(user["role"], []): abort(403) data = request.get_json() new_id = f"rpt-{len(_reports)+1:03d}" _reports[new_id] = {"id": new_id, "workspace_id": user["workspace_id"], "title": data.get("title"), "owner_id": user["user_id"]} return jsonify(_reports[new_id]), 201
@app.route("/api/reports/<report_id>/download", methods=["POST"]) def download_report(report_id): report = _reports.get(report_id) if report is None: abort(404) return jsonify({"url": f"https://cdn.example.com/reports/{report_id}.pdf"})
@app.route("/api/reports/<report_id>", methods=["DELETE"]) def delete_report(report_id): user = get_current_user() if user["role"] != "admin": abort(403) if report_id not in _reports: abort(404) del _reports[report_id] return "", 204
if name == "main": app.run(debug=True) =============== END FILE ===============