Skip to main content
Version: v2

Security & Compliance

Overview

The Convenient Checkout platform processes sensitive customer and financial data. Every engineer must follow strict data protection, clean code, and security best practices. These standards protect our customers, ensure regulatory readiness, and maintain the trust of merchants who integrate with our platform.


Data Protection Rules

What We Must Never Do

RuleDetail
Never log full card numbersCard numbers (PAN) must never appear in logs, error messages, or database fields
Never log CVV/CVCCard verification values must never be stored or logged anywhere
Never store raw card dataAll card data is tokenized by Stripe; we only store last-four, brand, expiry
Never expose sensitive data in responsesAPI responses must only include masked/truncated card details
Never log full SSNOnly ssnLastFour is permissible; full SSN must never be stored or logged
Never log full bank account numbersOnly last-four digits may appear in logs or responses

What We Must Always Do

RuleDetail
Mask in logsIf any card-adjacent or customer-sensitive data appears in logs, mask all but last 4 digits
Encrypt at restDatabase fields containing PII use column-level encryption
Encrypt in transitAll inter-service communication uses TLS 1.2+
Rotate secretsStripe API keys and database credentials rotated per policy
Audit trailEvery state transition must be recorded with timestamp, actor, and reason
Minimize data collectionOnly collect and store data that is required for the business operation
Data Protection

Logging or storing full card numbers (PAN), CVV, full SSN, or full bank account numbers is a serious data protection violation. When in doubt, consult the Security team before adding any logging around payment method or customer data.


OAuth2 Scope Enforcement

Scope Matrix

ScopeWhat It AllowsWho Gets It
merchantCreate/read payments, refunds, sessions; cancel; captureMerchant backend systems
userCreate payments (widget-initiated), read paymentsCheckout widget
merchant-pciCreate token payments with raw card dataCertified merchant systems

Validation Rules

  1. The API gateway validates the OAuth2 token before the request reaches the service.
  2. The X-Merchant-Id header must match a merchant linked to the token's clientId. Mismatch → 403 Forbidden.
  3. The service must not re-implement token validation but may read claims for audit logging.

Input Validation & Sanitization

Defense-in-Depth Layers

LayerWhat It Validates
OpenAPI schemaTypes, formats, enums, min/max, patterns, required fields
Controller annotations@Valid, @NotNull, @Size, @Pattern on DTOs
Service layerCross-field rules (allocation sum, authorization flag combinations)
Repository layerDatabase constraints (unique indexes, foreign keys, check constraints)

Specific Rules

InputValidationRejection
amountInteger, min=1, max=100,000,000 (cents)400 if out of range
merchantTransactionIdString, 1-50 chars400 if empty or too long
emailRegex: ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$400 if malformed
ssnLastFourExactly 4 digits: ^\d{4}$400 if malformed
zip5Exactly 5 digits: ^[0-9]{5}$400 if malformed
statementDescriptorSuffix1-10 chars, alphanumeric + space/dot/hyphen, must contain letter400 if invalid
metadata keys1-40 chars per key, 1-100 chars per value, max 20 entries400 if exceeded
paymentAllocations1-2 items, each must have amount ≥ 1400 if violated
paymentCancellationReasonOne of: DUPLICATE, FRAUDULENT, REQUESTED_BY_CUSTOMER, ABANDONED400 if invalid

Sensitive Data in Logs

Allowed to Log

FieldExample
paymentId550e8400-e29b-41d4-a716-446655440000
merchantTransactionIdorder-12345
merchantIdb955db5e-aef2-47de-bbb9-c80b9cc16e8f
statusCOMPLETED
amount15000
Card lastFour4242
Card brandvisa

Never Log

FieldWhy
Full card number (PAN)Sensitive financial data
CVV / CVCSensitive financial data
Full SSNPII — personally identifiable information
Full bank account numberSensitive financial data / PII
Bank routing numberPII
OAuth token valueSecurity — could be replayed
Stripe secret API keySecurity — grants full access

Log Sanitization

User-controlled strings must be sanitized before logging using LogSanitizationUtil.sanitizeForLog(). This strips \n/\r characters that could be used to forge or inject fake log entries.

// Correct — sanitize all user-supplied strings before logging
log.info("Processing refund for merchantTransactionId: {}",
LogSanitizationUtil.sanitizeForLog(request.getMerchantTransactionId()));

log.error("Payment failed - PaymentId: {}, Message: {}",
LogSanitizationUtil.sanitizeForLog(
ex.getPaymentResponse() != null ? ex.getPaymentResponse().getId() : null),
ex.getMessage(), ex);

// Incorrect — raw user input in log statement
log.info("MerchantTxId: {}", request.getMerchantTransactionId()); // ❌
note

LogSanitizationUtil currently lives in wallet-payment-service and should be migrated to wallet-event-commons so all services can use it consistently. See improvement roadmap.


Merchant Scoping in Code

Every resource fetch must verify merchantId ownership before returning data. Return 404 (not 403) to prevent resource existence leakage:

// Correct — ownership check returns 404 on mismatch
private Mono<Transaction> validateMerchantOwnership(UUID merchantId, Transaction transaction) {
if (!transaction.getMerchantId().equals(merchantId)) {
log.error("Requested merchantID/Payment MerchantId do not match. "
+ "requestedMerchantId={}, resourceMerchantId={}",
merchantId, transaction.getMerchantId());
return Mono.error(new PaymentNotFoundException("Payment information not found"));
}
return Mono.just(transaction);
}

Dependency Management & Vulnerabilities

PracticeRequirement
Dependency scanningAll services must run automated CVE scanning in CI pipelines
Upgrade cadenceCritical/High CVEs patched within 7 days; Medium within 30 days
No end-of-life dependenciesDependencies past EOL must be upgraded or replaced
Transitive dependenciesMonitor transitive dependencies for vulnerabilities, not just direct
Lock filesAlways commit lock files (pom.xml dependency versions pinned)
Secret detectionUse pre-commit hooks to prevent committing secrets, API keys, or credentials

Clean Code & Best Practices

PracticeRequirement
Code coverageMinimum 80% unit test coverage on new code; strive for higher on critical paths
Code reviewAll PRs require at least 1 reviewer; commons library PRs require 2
Static analysisLinting and static analysis must pass in CI before merge
No dead codeRemove unused imports, methods, classes — don't comment them out
Single responsibilityEach class/method has one clear purpose
Meaningful namesVariables, methods, and classes named for intent, not abbreviation
Error handlingNo swallowed exceptions; every catch block must log or propagate meaningfully

Audit Trail Requirements

Every state transition must produce an audit record containing:

FieldDescription
paymentIdThe resource being modified
previousStatusStatus before transition
newStatusStatus after transition
actorWho initiated (merchantId, system, stripe-webhook)
reasonWhy (e.g., REQUESTED_BY_CUSTOMER, stripe_charge_succeeded)
timestampUTC ISO 8601
requestIdCorrelation ID for tracing