Skip to content

feat(kilo-pass): enforce duplicate-card purchase window#3768

Open
jeanduplessis wants to merge 2 commits into
mainfrom
kilo-pass-abuse
Open

feat(kilo-pass): enforce duplicate-card purchase window#3768
jeanduplessis wants to merge 2 commits into
mainfrom
kilo-pass-abuse

Conversation

@jeanduplessis
Copy link
Copy Markdown
Contributor

@jeanduplessis jeanduplessis commented Jun 5, 2026

Summary

Blocks rapid cross-account Kilo Pass card reuse during the 24 hours after its first permanent fingerprint claim, while allowing same-user reuse and later cross-account purchases.

Why this change is needed

The previous duplicate-card gate could prevent card reuse for months while another account retained an active subscription and could run again on renewals. A rolling accepted-purchase implementation would narrow that behavior but introduce another persistent anti-abuse model alongside existing fingerprint claims and issuance history.

The intended threat model is rapid cross-account reuse shortly after a card first appears, not continuous rolling enforcement after every later purchase.

How this is addressed

  • Reuses permanent welcome-promo fingerprint claims as the atomic first-card-claim record and cooldown timestamp.
  • Resolves first claimant through the claim's source invoice, issuance, and subscription.
  • Blocks different-user reuse only while the first claim is strictly less than 24 hours old.
  • Allows same-user reuse and cross-account reuse at exactly 24 hours or later without refreshing the first claim.
  • Limits cancellation enforcement to positive initial Stripe monthly invoices; renewals, yearly purchases, and zero-dollar starts skip the gate.
  • Shares exact settled-payment resolution with welcome-promo decisions and never falls back to attached, default, or locally stored cards.
  • Uses successful duplicate-block audits for blocked replay authority and matching committed issuances for allowed or fail-open replay authority.
  • Removes the branch-only accepted-purchase table and migration.

Human Verification

  • Ran targeted duplicate-card, invoice-paid, checkout, user-retention, settlement-resolution, and email suites: 305 tests passed.
  • Verified migration history bootstraps an empty database.
  • Verified schema synchronization; schema suite passes 12 of 13 tests, with one unrelated pre-existing enum-registry mismatch.
  • Completed independent logic, security, data, type-safety, resource, and maintainability reviews with no findings.

Reviewer Notes

Human Reviewer Flags

  • The cooldown is intentionally anchored to the permanent first fingerprint claim and is not refreshed by later allowed purchases.
  • Existing fingerprint claims participate immediately. Missing first-claimant attribution fails open.
  • A card allowed after 24 hours remains ineligible for welcome promo and Kilo Pass referral conversion because its permanent claim remains unchanged.
  • Successful duplicate-block audits are authoritative blocked-replay evidence; matching committed issuances are authoritative allowed or fail-open replay evidence.
  • Stripe cancellation and refund remain best effort inside the database transaction. Current cancellation-email copy states that the charge will be refunded.

Code Reviewer Agent

Code Reviewer Notes
  • First-claim uniqueness atomically selects the winner for concurrent card use; no new digest lock or accepted-purchase table remains.
  • The exact settled card is resolved once per invoice attempt and shared between duplicate-card and welcome-promo decisions.
  • Duplicate audit and operational context contain a fingerprint digest and first-claim identifiers, never the raw fingerprint.
  • Blocked handling occurs before scheduled-change credits, issuance, referrals, and affiliate sales.

)
);

for (const record of [...blockAudits, ...issuanceRecords]) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: False-positive attribution conflict on late replay of an initial invoice

The issuanceRecords query uses OR(stripe_invoice_id = X, stripe_subscription_id = Y), which returns ALL issuances for the subscription — including issuances from later billing cycles (months 2, 3, …). The conflict loop then checks that every returned record has exactly stripeInvoiceId === params.stripeInvoiceId, stripeSubscriptionId === params.stripeSubscriptionId, and kiloUserId === params.kiloUserId. Issuances from later invoices have a different stripeInvoiceId, so they trip the conflict guard and throw — even though there is no real conflict.

Concrete scenario:

  1. Month-1 initial invoice is processed successfully → issuance stripe_invoice_id = in_month1 is written.
  2. Months 2–6 are processed normally → issuances in_month2in_month6 are written.
  3. Stripe re-delivers the month-1 webhook (late retry / infra replay).
  4. loadDuplicateCardReplayAuthority is called with stripeInvoiceId = in_month1.
  5. The OR query returns all 6 issuances. Months 2–6 have stripeInvoiceId !== in_month1reportAttributionConflict throws and invoice handling is aborted.

The function's purpose is to detect whether this specific invoice was already handled; the subscription-scoped OR branch is intended for the blocked-audit check, where a matching subscription with a different invoice genuinely indicates something went wrong. For the issuance side the intent is only to find an issuance linked to params.stripeInvoiceId. Limiting the issuance query to WHERE stripe_invoice_id = params.stripeInvoiceId (dropping the subscription OR) would correctly identify the allowed-replay case and avoid false conflicts.

@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Jun 5, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

A false-positive attribution conflict in loadDuplicateCardReplayAuthority will throw and abort initial-invoice replay for subscriptions that have since accumulated multiple monthly issuances.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/kilo-pass/card-fingerprint-gate.ts 256 OR-based issuance query causes false-positive conflict on late replay
Files Reviewed (9 files)
  • .specs/kilo-pass.md
  • apps/web/src/emails/kiloPassDuplicateCardCanceled.html
  • apps/web/src/lib/kilo-pass/card-fingerprint-gate.test.ts
  • apps/web/src/lib/kilo-pass/card-fingerprint-gate.ts — 1 issue
  • apps/web/src/lib/kilo-pass/stripe-handlers-invoice-paid.test.ts
  • apps/web/src/lib/kilo-pass/stripe-handlers-invoice-paid.ts
  • apps/web/src/lib/kilo-pass/stripe-handlers-utils.test.ts
  • apps/web/src/lib/kilo-pass/stripe-handlers-utils.ts
  • apps/web/src/lib/purchase-emails.test.ts

Fix these issues in Kilo Cloud


Reviewed by claude-4.6-sonnet-20260217 · 8,286,029 tokens

Review guidance: REVIEW.md from base branch main

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