Skip to content

fix(security): hash reset codes and session tokens, coordinate reset transactionally (#54) - #56

Merged
nishark90 merged 6 commits into
mainfrom
feature/54-refresh-token-rotation-and-hardening
Sep 20, 2026
Merged

nishark90 merged 6 commits into
mainfrom
feature/54-refresh-token-rotation-and-hardening

Conversation

@rajeshm20

Copy link
Copy Markdown
Owner

Resolves P0 security findings:

  • Cryptographically secure OTP generation with CSPRNG and rejection sampling.
  • HMAC-SHA256 hashed OTPs and SHA-256 hashed session tokens (never stored in plaintext).
  • Constant-time comparison for OTP validation.
  • Invalidation of prior tokens and strict attempt limits.
  • Atomic single-use consumption of reset session tokens.
  • Transactionally coordinated password update and active refresh session revocation.

@rajeshm20
rajeshm20 force-pushed the feature/54-refresh-token-rotation-and-hardening branch from 97c20ce to 810c7ac Compare September 20, 2026 08:17
@rajeshm20

Copy link
Copy Markdown
Owner Author

Assessment: Yes — both issues are fixed in the latest PR #56

The latest PR head is commit aa42797ab0b0ca3b9160e59ef735b68466aa3abf.

Partially migrated schema

Status: Fixed

HardenPasswordResetTokens.swift now reconciles each hardened column independently.

PostgreSQL

Uses independent ADD COLUMN IF NOT EXISTS clauses for:

  • code_hash
  • session_token_hash
  • code_expires_at
  • session_expires_at
  • created_at

MySQL

Reads information_schema.COLUMNS, then independently adds every missing column.

SQLite

Reads PRAGMA table_info(...), then independently adds every missing column.

Therefore, a schema containing only code_hash, or any arbitrary subset of hardened columns, should now be completed safely.

Missing individual hardened columns

Status: Fixed

The latest migration no longer gates all additions on the presence of code_hash.

This previous failure mode:

Text
code_hash exists

session_token_hash missing
code_expires_at missing
session_expires_at missing
created_at missing

is now handled correctly.

Supporting tests added

The PR now includes tests for:

  • recovery from a schema containing only code_hash;
  • recovery from an arbitrary subset of hardened columns;
  • migration idempotence by running the migration multiple times;
  • legacy plaintext schema migration;
  • removal of plaintext columns;
  • invalidation of existing token rows.

Relevant additions are in:

Updated result

Finding Current status
Partially migrated schema Fixed
Missing individual hardened columns Fixed
Arbitrary subset recovery Implemented and tested
Migration rerun/idempotence Implemented and tested

Conclusion: the previously identified partial-migration recovery issue is fixed in the latest commit. The remaining step is to confirm the latest CI run has completed successfully, particularly against the database driver intended for production.

Assessment: Yes — both issues are fixed in the latest PR #56

The latest PR head is commit aa42797ab0b0ca3b9160e59ef735b68466aa3abf.

Partially migrated schema

Status: Fixed

HardenPasswordResetTokens.swift now reconciles each hardened column independently.

PostgreSQL

Uses independent ADD COLUMN IF NOT EXISTS clauses for:

code_hash
session_token_hash
code_expires_at
session_expires_at
created_at
MySQL

Reads information_schema.COLUMNS, then independently adds every missing column.

SQLite

Reads PRAGMA table_info(...), then independently adds every missing column.

Therefore, a schema containing only code_hash, or any arbitrary subset of hardened columns, should now be completed safely.

Missing individual hardened columns

Status: Fixed

The latest migration no longer gates all additions on the presence of code_hash.

This previous failure mode:

Text
code_hash exists
session_token_hash missing
code_expires_at missing
session_expires_at missing
created_at missing
is now handled correctly.

Supporting tests added

The PR now includes tests for:

recovery from a schema containing only code_hash;
recovery from an arbitrary subset of hardened columns;
migration idempotence by running the migration multiple times;
legacy plaintext schema migration;
removal of plaintext columns;
invalidation of existing token rows.
Relevant additions are in:

HardenPasswordResetTokens.swift
StudentAppBackendTests.swift
Specs/partial-migration-recovery/spec.md
Updated result

Finding Current status
Partially migrated schema Fixed
Missing individual hardened columns Fixed
Arbitrary subset recovery Implemented and tested
Migration rerun/idempotence Implemented and tested
Conclusion: the previously identified partial-migration recovery issue is fixed in the latest commit. The remaining step is to confirm the latest CI run has completed successfully, particularly against the database driver intended for production.

@nishark90
nishark90 merged commit 764eb1e into main Sep 20, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Development

Successfully merging this pull request may close these issues.

2 participants