Skip to content

fix: address security issues #105, #106, and #125 - #188

Open
dripscodes wants to merge 1 commit into
terngunan:mainfrom
dripscodes:fix/security-105-106-125
Open

dripscodes wants to merge 1 commit into
terngunan:mainfrom
dripscodes:fix/security-105-106-125

Conversation

@dripscodes

@dripscodes dripscodes commented Oct 24, 2026 •

Copy link
Copy Markdown

Summary

Patches three security issues across the backend waitlist API and the merchant_registry Soroban contract.


closes #125 · P2 · waitlist/join exposes unsubscribeToken in HTTP response (backend)

Problem: WaitlistService.join() returned the raw WaitlistEntry TypeORM entity, which included the unsubscribeToken secret in every HTTP response. Because the endpoint is public (no auth required), any client application logging response bodies could inadvertently capture this GDPR-deletion token.

Fix:

  • Added WaitlistEntryResponseDto (omits unsubscribeToken).
  • WaitlistService.join() now destructs the saved entity, drops the token, and returns the sanitised DTO.
  • Controller spec extended with an explicit assertion: the response must not contain unsubscribeToken.

#105 · merchant_registry: register_merchant allows empty business name (contract)

Problem: update_merchant already guards against name.len() == 0, but register_merchant had no equivalent check, so an admin could store a merchant record with an empty name string.

Fix:

  • Added if name.len() == 0 { panic!("Merchant name cannot be empty") } at the top of register_merchant, mirroring the existing guard in update_merchant.
  • New test: test_register_merchant_empty_name_panics.

#106 · merchant_registry: unbounded page_size in merchants() risks gas exhaustion (contract)

Problem: merchants() accepted any page_size value, allowing a caller to trigger an arbitrarily large number of persistent-storage reads in a single transaction, potentially exhausting the Soroban gas budget.

Fix:

  • Added MAX_PAGE_SIZE = 100 constant.
  • merchants() now computes effective_page_size = page_size.min(MAX_PAGE_SIZE) and uses it throughout the loop.
  • New tests: test_merchants_page_size_capped_at_max and test_merchants_page_size_capped_returns_correct_slice.

Files changed

File Change
backend/src/waitlist/dto/waitlist-entry-response.dto.ts New – sanitised join response DTO
backend/src/waitlist/waitlist.service.ts Return WaitlistEntryResponseDto from join()
backend/src/waitlist/waitlist.controller.spec.ts Assert unsubscribeToken absent in join response
settliq_contracts/contracts/merchant_registry/src/lib.rs Empty-name guard (#105) + page_size cap (#106)
settliq_contracts/contracts/merchant_registry/src/test.rs New tests for #105 and #106

Testing

  • Backend: jest waitlist.controller.spec.ts — existing + new assertion pass.
  • Contracts: cargo test -p merchant_registry — all existing tests pass; new empty-name and page_size-cap tests pass.

Closes #105, #106, #125

…nan#125

terngunan#125 (P2 – backend): strip unsubscribeToken from /waitlist/join response
- Add WaitlistEntryResponseDto that omits unsubscribeToken
- Update WaitlistService.join() to return the sanitised DTO
- Add controller spec assertion: response must not contain unsubscribeToken

terngunan#105 (merchant_registry): reject empty business name in register_merchant
- Mirror the same guard already present in update_merchant
- Add test: test_register_merchant_empty_name_panics

terngunan#106 (merchant_registry): cap unbounded page_size in merchants()
- Add MAX_PAGE_SIZE = 100 constant
- Compute effective_page_size = page_size.min(MAX_PAGE_SIZE) before use
- Add tests: test_merchants_page_size_capped_at_max and
  test_merchants_page_size_capped_returns_correct_slice
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant