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 project management SaaS product has a REST API with three roles: admin, member, and viewer. The permission logic is scattered across route handlers and there is no single source of truth. The team wants to formalize the access control model and add automated tests before the next audit.
The existing middleware and route code is provided below. Review the code to understand the current permission model, then produce a formal authorization matrix and a test suite that verifies it.
Produce the following files:
auth_matrix.yaml or auth_matrix.json — a machine-readable authorization matrix you derived from the code, covering all endpoints and roles with their expected allow/deny outcomestest_auth.py (or test_auth.js) — an automated test suite that verifies the matrix. Use a stub/mock server or simple in-memory handler — no real server setup required.security_notes.md — a brief explanation of the testing strategy and any security concerns you identifiedThe following files are provided as inputs. Extract them before beginning.
=============== FILE: inputs/app.py =============== from flask import Flask, jsonify, request, abort, g
app = Flask(name)
ROLES_PERMISSIONS = { "admin": ["projects:list", "projects:create", "projects:read", "projects:update", "projects:delete", "projects:export"], "member": ["projects:list", "projects:create", "projects:read", "projects:update"], "viewer": ["projects:list", "projects:read"], }
def require_auth(f): def wrapper(*args, **kwargs): token = request.headers.get("X-Role") if not token or token not in ROLES_PERMISSIONS: abort(401) g.role = token return f(*args, **kwargs) wrapper.name = f.name return wrapper
def check_perm(permission): if permission not in ROLES_PERMISSIONS.get(g.role, []): abort(403)
@app.route("/projects", methods=["GET"]) @require_auth def list_projects(): check_perm("projects:list") return jsonify([{"id": 1, "name": "Alpha"}])
@app.route("/projects", methods=["POST"]) @require_auth def create_project(): check_perm("projects:create") return jsonify({"id": 2, "name": request.json.get("name")}), 201
@app.route("/projects/int:pid", methods=["GET"]) @require_auth def get_project(pid): check_perm("projects:read") return jsonify({"id": pid, "name": "Alpha"})
@app.route("/projects/int:pid", methods=["PUT"]) @require_auth def update_project(pid): check_perm("projects:update") return jsonify({"id": pid, "name": request.json.get("name")})
@app.route("/projects/int:pid", methods=["DELETE"]) @require_auth def delete_project(pid): check_perm("projects:delete") return "", 204
@app.route("/projects/int:pid/export", methods=["POST"]) @require_auth def export_project(pid): check_perm("projects:export") return jsonify({"status": "exporting"})
if name == "main": app.run(debug=True) =============== END FILE ===============