Skip to content

fix(security): financial input validation (positive amounts, mass-assignment, confirmation entropy)#121

Merged
telivity-otaip merged 1 commit into
mainfrom
claude/financial-input-validation
Jun 17, 2026
Merged

fix(security): financial input validation (positive amounts, mass-assignment, confirmation entropy)#121
telivity-otaip merged 1 commit into
mainfrom
claude/financial-input-validation

Conversation

@telivity-otaip

Copy link
Copy Markdown
Collaborator

Closes the financial input-validation cluster the 5-reviewer adversarial pass found after confirming tenant isolation is solid. These are real, exploitable within-tenant integrity bugs (not cross-tenant). One bounded PR — no loop.

HIGH

  • Positive-amount validation. New shared @IsMoneyString validator (parses via decimal.js, rejects NaN/Infinity and — by default — zero/negatives).
    • payment create + authorize amount → must be > 0.
    • reservation.totalAmount≥ 0 (comp rooms allowed).
    • folio charge amount: still a valid decimal at the DTO layer (credits are legit), but the service now rejects a non-positive amount unless type='adjustment' or a reversal. (Negatives previously inverted folio balances / manufactured credit; the refund path was already guarded, these weren't.) taxAmount ≥ 0.
  • Kill setRateOverride mass-assignment. Real SetRateOverrideDto replaces @Body() override: any, so the global ValidationPipe strips unknown keys and bounds adjustmentValue (was spread verbatim into the config JSON column).

MEDIUM

  • Confirmation numbers are now 128-bit random (Crockford base32) instead of HAIP-{timestamp}-{4hex} (~16 bits) — closes within-tenant booking enumeration. Generation-only change; existing rows still resolve.
  • Rate limiter ignores X-Forwarded-For unless RATE_LIMIT_TRUST_PROXY=true (default off) — a client can't rotate the header to dodge the limit.
  • TaxController now uses ParseUUIDPipe on every id/propertyId param (malformed → 400, not a 500).

LOW

  • folio.postCharge validates originalChargeId whenever present (not only on reversals) — removes a dangling cross-tenant soft reference.

Out of scope (noted)

Guest email-oracle on /connect/book (guests are cross-property by design — product call), connect-gpt guest-address log redaction (separate tool).

Verify

New specs: is-money-string.validator, confirmation-token (entropy/format/no-collision), rate-limit XFF default-ignore, folio charge sign rules. 913 api tests green, typecheck + lint clean. Demo unaffected (validation only tightens inputs; AUTH-off paths unchanged).

🤖 Generated with Claude Code


Generated by Claude Code

A 5-reviewer adversarial pass confirmed tenant isolation is solid and found a
financial input-validation cluster (real, within-tenant integrity bugs). Fixes:

- Positive-amount validation: new shared @IsMoneyString validator (decimal.js).
  payment create/authorize amount > 0; reservation totalAmount >= 0; folio
  charge amount must be a valid decimal AND the service rejects non-positive
  unless type=adjustment or a reversal (negatives previously inverted folio
  balances / manufactured credit).
- Kill setRateOverride mass-assignment: real SetRateOverrideDto replaces
  @Body() any, so the ValidationPipe strips unknown keys and bounds
  adjustmentValue (was spread verbatim into the config JSON).
- Confirmation numbers are now 128-bit random (Crockford base32), not
  HAIP-{timestamp}-{4hex}, closing within-tenant booking enumeration.
- Rate limiter ignores X-Forwarded-For unless RATE_LIMIT_TRUST_PROXY=true, so
  the brute-force brake can't be bypassed by rotating the header.
- TaxController: ParseUUIDPipe on all id/propertyId params (malformed -> 400).
- folio postCharge validates originalChargeId whenever present, not only on
  reversals (removes a dangling cross-tenant soft reference).

New specs (money validator, confirmation-token entropy, rate-limit XFF, folio
charge sign rules) + existing suite: 913 green; typecheck + lint clean.
@telivity-otaip telivity-otaip merged commit 0177252 into main Jun 17, 2026
4 checks passed
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.

2 participants