Context
Follow-up from PR #402, which closed the anonymous-access CRITICAL by adding RequireAuth + permission_guard! (LogsRead/AnalyticsRead) to all 12 /api/proxy-logs* handlers. Authentication is now enforced.
Remaining gap (MEDIUM; HIGH for Temps Cloud multi-tenant)
None of the proxy-log handlers scope reads to the caller's team membership. An authenticated user with logs:read/analytics:read — or a deployment token with analytics:read — can read another project's data:
- (a)
project_id/project_ids filter handlers: get_proxy_logs, get_today_stats, get_time_bucket_stats, get_projects_health, get_ai_agent_breakdown, get_ai_agent_timeline, get_ai_page_breakdown, get_ai_status_breakdown, get_ai_agent_pages — pass an arbitrary project id and read that project's data.
- (b) by-id / by-request-id lookups:
get_proxy_log_by_id, get_proxy_log_by_request_id carry no project filter at all — must check the returned row's project_id post-fetch.
- (c) deployment-token cross-project:
project_scope_guard! is not called in any handler.
For single-tenant self-hosted this is low-risk (all authenticated users co-operate the instance). For Temps Cloud multi-tenant it is a real HIGH and must be fixed before other tenants are onboarded to these endpoints.
Plan
- Thread
Option<Arc<dyn temps_core::ProjectAccessChecker>> onto the proxy plugin's route state (resolve in configure_routes via context.get_service::<dyn ProjectAccessChecker>()); the handlers currently take State<Arc<ProxyLogService>>.
- For (a): add
project_scope_guard!(auth, project_id) + project_access_guard!(auth, project_id, checker) after permission_guard!.
- For (b): post-fetch check of
log.project_id before returning.
- Add
"temps-proxy" to expected_crates in project_access_guard_coverage_snapshot (temps-auth/src/permission_guard.rs) so the ADR-028 coverage test enforces it.
There is an in-code NOTE at get_projects_health marking the spot.
Context
Follow-up from PR #402, which closed the anonymous-access CRITICAL by adding
RequireAuth+permission_guard!(LogsRead/AnalyticsRead) to all 12/api/proxy-logs*handlers. Authentication is now enforced.Remaining gap (MEDIUM; HIGH for Temps Cloud multi-tenant)
None of the proxy-log handlers scope reads to the caller's team membership. An authenticated user with
logs:read/analytics:read— or a deployment token withanalytics:read— can read another project's data:project_id/project_idsfilter handlers:get_proxy_logs,get_today_stats,get_time_bucket_stats,get_projects_health,get_ai_agent_breakdown,get_ai_agent_timeline,get_ai_page_breakdown,get_ai_status_breakdown,get_ai_agent_pages— pass an arbitrary project id and read that project's data.get_proxy_log_by_id,get_proxy_log_by_request_idcarry no project filter at all — must check the returned row'sproject_idpost-fetch.project_scope_guard!is not called in any handler.For single-tenant self-hosted this is low-risk (all authenticated users co-operate the instance). For Temps Cloud multi-tenant it is a real HIGH and must be fixed before other tenants are onboarded to these endpoints.
Plan
Option<Arc<dyn temps_core::ProjectAccessChecker>>onto the proxy plugin's route state (resolve inconfigure_routesviacontext.get_service::<dyn ProjectAccessChecker>()); the handlers currently takeState<Arc<ProxyLogService>>.project_scope_guard!(auth, project_id)+project_access_guard!(auth, project_id, checker)afterpermission_guard!.log.project_idbefore returning."temps-proxy"toexpected_cratesinproject_access_guard_coverage_snapshot(temps-auth/src/permission_guard.rs) so the ADR-028 coverage test enforces it.There is an in-code NOTE at
get_projects_healthmarking the spot.