Skip to content

fix(backend): close D3 (registration-form self-path) and D6 (attachment window bypass) - #194

Merged
caviri merged 2 commits into
developfrom
fix/feedback-security-d3-d6-20260819
Aug 19, 2026
Merged

fix(backend): close D3 (registration-form self-path) and D6 (attachment window bypass)#194
caviri merged 2 commits into
developfrom
fix/feedback-security-d3-d6-20260819

Conversation

@caviri

@caviri caviri commented Aug 19, 2026

Copy link
Copy Markdown
Member

Two backend authorization holes from the audit, same shape as the D1/D2 fix already merged.

D3 — registration-form self-path had no gate

resolveRegistrationTarget required Hackathon:Write for the on_behalf_of path but returned the caller unconditionally on the self path. Any authenticated user could SubmitRegistrationForm for any hackathon — a private one they were never invited to — which (a) wrote a FormResponse row into that event and (b) turned the validation errors into a form-schema oracle (they name missing/unknown fields).

Fix: require a Participant row on the self path (Join writes it; a private event's Join needs an invite). Waitlisted participants pass — they're exactly who still needs their form. The check runs before the form is loaded, so a non-participant is refused before any schema detail leaks.

Pinned: registration_gate_test.go — non-participant → PermissionDenied; waitlisted joiner → passes the gate (reaching the form-not-defined FailedPrecondition, a different code = proof). This handler had zero prior tests.

D6 — attachment upload escaped the submissions window + capability

The SUBMISSION_ATTACHMENT presign checked casbin Submission:Write but not requireWindowOpen(windowSubmissions) or requireCapability(CreateProjectSubmissions) — the two gates CreateSubmission/EditSubmission/FinalizeSubmission all enforce. So a team could upload attachments after the deadline, or while the submit capability was off.

Fix: add the same two calls the submission handlers use, on the hackathon id already resolved from the submission's team.

Verification (devcontainer, fast tier)

  • go build ./... clean
  • go test -tags "test unittest" ./internal/service/... ./internal/middleware/... — OK (D3's 2 new specs pass)
  • gofmt -l empty

Follow-up (noted, not in this PR)

A dedicated D6 attachment-window integration test — the fix reuses the exact gate functions CreateSubmission's tests already exercise, but a call-site test would pin the wiring. The submission chain has no reusable setup helper (~70 lines inline per test), so it's deferred rather than bloating this PR.

caviri added 2 commits August 19, 2026 02:56
resolveRegistrationTarget checked Hackathon:Write for the on_behalf_of path but
returned the caller unconditionally on the self path. So any authenticated user
could POST SubmitRegistrationForm for ANY hackathon — a private one they were
never invited to included — which both wrote a FormResponse row into that event
and turned the validation errors into a form-schema oracle (they name missing
and unknown fields).

Require a Participant row on the self path. Join is what writes it, and a
private event's Join requires an invite, so a participant row is the proof the
caller belongs in this form. Waitlisted participants pass — they are exactly who
still needs to submit or correct their answers. The check runs before the form
is loaded, so a non-participant is refused before any schema detail leaks.

Pins it: registration_gate_test.go asserts a non-participant gets
PermissionDenied and a waitlisted joiner passes the gate (reaching the
form-not-defined FailedPrecondition — a different code is the proof).
…indow (D6)

The SUBMISSION_ATTACHMENT presign path checked casbin Submission:Write but not
the submissions window or the create_project_submissions capability — the two
gates every other submission write goes through (CreateSubmission,
EditSubmission, FinalizeSubmission in team_service.go). So a team could presign
and upload an attachment after the deadline closed, or while the submit
capability was off, slipping work in past the window the submission handlers
enforce.

Add the same requireWindowOpen(windowSubmissions) + requireCapability(
CreateProjectSubmissions) calls the submission handlers use, on the same
hackathon id already resolved from the submission's team.
@caviri
caviri merged commit 8352db1 into develop Aug 19, 2026
1 check passed
@caviri
caviri deleted the fix/feedback-security-d3-d6-20260819 branch August 19, 2026 00:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant