Skip to content

Close a draft-roster leak, CSV formula injection, and stale role caches - #427

Merged
aamoghS merged 1 commit into
devfrom
fix/api-hardening
Sep 25, 2026
Merged

aamoghS merged 1 commit into
devfrom
fix/api-hardening

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Findings from an API audit, each verified against the code.

  • CSV formula injection (resume book index.csv): member-typed names/schools/majors starting with = + - @ ran as formulas when staff opened the file in Excel/Sheets (e.g. =HYPERLINK leaking the row). Those cells now get a leading apostrophe.
  • Draft roster leak: hackathon.participants (public) and team.list skipped assertHackathonVisible, which schedule/gallery/results already apply. Anyone with a draft edition's uuid could list its participants and teams. Now NOT_FOUND for non-staff.
  • Stale judge nav: judge.create / judge.remove didn't clear the role cache or portal context (only approval did): new judges waited up to 5 min for the Judge tab; removed judges kept a tab that every procedure refused.
  • Stale member caches: clearMembershipCaches now also evicts member:history:<id> and the staff directory (members:list:*), which previously only expired.

Tests

Updated three roster tests to use a visible edition; added "hides a draft hackathon's participant list". Typecheck 9/9, lint 8/8, pnpm test 829 passing.

- Resume book index.csv: names, schools and majors are member-typed, and
  a leading = + - @ made Excel/Sheets run it as a formula when staff
  opened the file (e.g. =HYPERLINK exfiltrating the row). Such cells now
  get a leading apostrophe.
- hackathon.participants (public) and team.list skipped
  assertHackathonVisible, which the schedule, gallery and results
  already apply, so anyone holding a draft edition's uuid could list its
  participants and teams. Both now answer NOT_FOUND for a draft to
  non-staff.
- judge.create and judge.remove did not clear the judge role cache or
  portal context (only approval did), so a new judge waited up to 5
  minutes for the Judge tab and a removed one kept a tab every procedure
  refused.
- clearMembershipCaches now also evicts member:history:<id> and the
  staff directory (members:list:*), which only ever expired.
@github-actions
github-actions Bot requested a review from aamoghS as a code owner September 25, 2026 03:09
@aamoghS aamoghS changed the title Feature: fix/api-hardening to dev Close a draft-roster leak, CSV formula injection, and stale role caches Sep 25, 2026
@aamoghS
aamoghS merged commit 7a3066b into dev Sep 25, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant