[Security][Decision] Should HttpCallback scheduled-task creation be admin-only (vs admin,staff)? #442

Closed
opened 2026-07-06 15:29:08 +00:00 by spikerj · 1 comment
Owner

Follow-up split from #438 (SSRF egress guard, resolved in backend PR #137).

The SSRF vulnerability is fixed — the HttpCallback runner now enforces a deny-internal egress policy. This ticket is the remaining authorization-scope decision, which is a policy call, not a bug:

ScheduledTasksController gates task creation [Authorize(Roles = "admin,staff")], so staff can create HttpCallback tasks (a server-side outbound-fetch primitive). Now that egress is locked to public destinations by default, the residual risk is low — but for defense-in-depth on a millions-of-kids platform, we may want the HttpCallback task type specifically restricted to admin.

Options:

  1. Leave as admin,staff — the egress guard is sufficient; staff automation is a legitimate use.
  2. Restrict HttpCallback to admin — per-task-type authz (staff keep the other task types; only the fetch primitive narrows to admin).

Option 2 is a small, bounded change (a per-task-type role check in the runner/consumer or a create-time gate). No default I can pick unilaterally — it depends on how broad "staff" is and whether staff-created callbacks are a real workflow. Happy to implement option 2 on a go-ahead.

Severity: Low (defense-in-depth; the exploitable SSRF is already closed).

Follow-up split from #438 (SSRF egress guard, resolved in backend PR #137). The SSRF *vulnerability* is fixed — the HttpCallback runner now enforces a deny-internal egress policy. This ticket is the remaining **authorization-scope decision**, which is a policy call, not a bug: `ScheduledTasksController` gates task creation `[Authorize(Roles = "admin,staff")]`, so **staff** can create `HttpCallback` tasks (a server-side outbound-fetch primitive). Now that egress is locked to public destinations by default, the residual risk is low — but for defense-in-depth on a millions-of-kids platform, we may want the `HttpCallback` task *type* specifically restricted to `admin`. **Options:** 1. **Leave as `admin,staff`** — the egress guard is sufficient; staff automation is a legitimate use. 2. **Restrict `HttpCallback` to `admin`** — per-task-type authz (staff keep the other task types; only the fetch primitive narrows to admin). Option 2 is a small, bounded change (a per-task-type role check in the runner/consumer or a create-time gate). No default I can pick unilaterally — it depends on how broad "staff" is and whether staff-created callbacks are a real workflow. Happy to implement option 2 on a go-ahead. Severity: Low (defense-in-depth; the exploitable SSRF is already closed).
Author
Owner

Resolved in backend PR #156 (merged to master). Implemented option 2: ScheduledTasksController.Create() now returns 403 when TaskType == "HttpCallback" and the caller is not admin (case-tolerant via SpikerSoftRoles.IsInRoleIgnoreCase); staff retain every other task type. Verified there's no per-type bypass — Update() can't change a task's TaskType and Trigger() only runs already-admin-authorized tasks, so a create-time gate is sufficient. Tests cover staff→Forbid, admin→Created, staff+other-type→Created. Closing.

Resolved in backend PR #156 (merged to `master`). Implemented option 2: `ScheduledTasksController.Create()` now returns 403 when `TaskType == "HttpCallback"` and the caller is not admin (case-tolerant via `SpikerSoftRoles.IsInRoleIgnoreCase`); staff retain every other task type. Verified there's no per-type bypass — `Update()` can't change a task's `TaskType` and `Trigger()` only runs already-admin-authorized tasks, so a create-time gate is sufficient. Tests cover staff→Forbid, admin→Created, staff+other-type→Created. Closing.
Sign in to join this conversation.