# Navigating FinTech Compliance: Our PCI-DSS Certification Journey
When building a payment platform processing $50M+ annually, compliance isn't optional—it's existential. Here's our complete PCI-DSS certification journey and practical implementation guide.
## What is PCI-DSS and Why It Matters
**PCI-DSS** (Payment Card Industry Data Security Standard) is a set of security standards ensuring all companies that accept, process, store or transmit credit card information maintain a secure environment.
**Why you need it**:
- Legal requirement for processing card payments
- Customers won't trust you without it
- Penalties for breach: $5K-100K per month + lawsuits
- Reputational damage is often unrecoverable
**Our Timeline**:
- Month 1-2: Gap assessment & planning
- Month 3-5: Implementation & remediation
- Month 6: QSA audit
- Month 7: Certification achieved ✅
**Cost**: $85K (security tools + consulting + audit fees)
## The 12 PCI-DSS Requirements (and How We Implemented)
### 1. Install and Maintain Firewall Configuration
**Requirement**: Protect cardholder data with firewalls.
**What we did**:
- AWS Security Groups: Whitelist only necessary IPs/ports
- Web Application Firewall (WAF): CloudFlare for DDoS protection
- Network segmentation: Cardholder Data Environment (CDE) isolated from other systems
**Implementation**:
```yaml
# AWS Security Group (Payment Service)
Inbound Rules:
- Port 443 (HTTPS): From API Gateway only
- Port 5432 (PostgreSQL): From App Server only
- SSH (22): From VPN only (specific IP ranges)
Outbound Rules:
- Port 443: To payment gateways only
- All other ports: Denied by default
```
**Cost**: $2K/month (CloudFlare Enterprise + AWS)
### 2. Don't Use Vendor-Supplied Defaults
**Requirement**: Change default passwords and remove unnecessary default accounts.
**What we did**:
- All servers provisioned with unique SSH keys (no passwords)
- Database admin usernames changed from "admin" to randomized
- Default ports changed (PostgreSQL from 5432 → 15432)
- All default accounts disabled
**Automated Check**:
```bash
# Script runs daily via cron
#!/bin/bash
# Check for default usernames
forbidden_users=("admin" "root" "postgres" "mysql")
for user in "${forbidden_users[@]}"; do
if id "$user" &>/dev/null; then
alert_security_team "Default user $user exists"
fi
done
```
### 3. Protect Stored Cardholder Data
**Requirement**: Encrypt cardholder data at rest.
**Critical**: We **never store full card numbers**. Instead, we use tokenization via Stripe/Xendit.
**Data Flow**:
```
User enters card → Frontend sends to Stripe → Stripe returns token
→ We store token only (useless if stolen)
```
**For PII we must store** (name, email, transaction amounts):
```javascript
// Encryption at rest using AES-256
const encryptPII = (data) => {
const cipher = crypto.createCipheriv(
'aes-256-gcm',
KEY_FROM_AWS_KMS, // Rotation policy: 90 days
IV
);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
};
```
**Database encryption**: AWS RDS encrypted volumes (AES-256)
**Key management**: AWS KMS with automatic rotation every 90 days
### 4. Encrypt Transmission of Cardholder Data
**Requirement**: Encrypt cardholder data across public networks.
**What we did**:
- TLS 1.3 for all API endpoints (no TLS 1.0/1.1 allowed)
- Certificate pinning in mobile apps
- HSTS header: Force HTTPS always
- HTTP → HTTPS redirect at load balancer
**nginx config**:
```nginx
server {
listen 443 ssl http2;
# Strong TLS config
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
# HSTS: Force HTTPS for 1 year
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
```
**Testing**: Monthly SSL Labs scan (Grade A+ required)
### 5. Use and Regularly Update Anti-Virus
**Requirement**: Protect systems against malware.
**What we did**:
- ClamAV on all servers (open-source antivirus)
- File upload scanning before storage
- Daily definition updates
- Weekly full system scans
**Automated scanning**:
```bash
# Scan all uploaded files
for file in /uploads/*; do
clamscan "$file"
if [ $? -ne 0 ]; then
rm "$file"
alert_security_team "Malware detected: $file"
fi
done
```
### 6. Develop and Maintain Secure Systems
**Requirement**: All systems and applications must be free from known vulnerabilities.
**What we did**:
- Monthly dependency audits: `npm audit`, `bundle audit`
- Automated patching for OS (AWS Systems Manager)
- Quarterly penetration testing by third-party
- Bug bounty program ($500-$5K per valid vulnerability)
**CI/CD Security Checks**:
```yaml
# GitLab CI pipeline
security_scan:
script:
- npm audit --audit-level=high # Fail on high/critical
- snyk test --severity-threshold=high
- trivy image --severity HIGH,CRITICAL
```
**Result**: Average time to patch critical vulnerabilities: 48 hours
### 7. Restrict Access to Cardholder Data
**Requirement**: Limit access to cardholder data on "need to know" basis.
**What we did**:
- Role-Based Access Control (RBAC)
- Only 3 engineers have production DB access (encrypted, logged)
- MFA required for all system access
- Principle of least privilege
**Access Levels**:
```
Level 1 (Dev): Read access to non-PII data
Level 2 (Senior Dev): Read access to masked PII
Level 3 (Lead/DevOps): Full access, all actions logged
Level 4 (Auditor): Read-only access to everything
```
**Audit Log** (every access logged):
```json
{
"timestamp": "2025-12-10T14:23:11Z",
"user": "dan.ramdani@danlabs.co",
"action": "SELECT",
"table": "transactions",
"ip": "203.0.113.42",
"mfa_verified": true
}
```
### 8. Assign Unique ID to Each Person
**Requirement**: Each user must have unique credentials.
**What we did**:
- No shared accounts (each engineer has their own)
- SSO via Google Workspace
- MFA enforced (Authy/Google Authenticator)
- Session timeout: 15 minutes idle, 8 hours max
**MFA Implementation**:
```javascript
// Login requires password + TOTP code
const login = async (email, password, totpCode) => {
const user = await verifyPassword(email, password);
if (!user) throw new Error('Invalid credentials');
const totpValid = speakeasy.totp.verify({
secret: user.mfaSecret,
encoding: 'base32',
token: totpCode,
window: 1 // Allow 30-second clock skew
});
if (!totpValid) throw new Error('Invalid MFA code');
return generateJWT(user);
};
```
### 9. Restrict Physical Access
**Requirement**: Restrict physical access to cardholder data.
**What we did** (cloud-only infrastructure):
- AWS data centers (SOC 2 certified)
- No on-premise servers
- Physical access controls managed by AWS
- Office network isolated from production
**For office**:
- Disk encryption on all laptops (BitLocker/FileVault)
- No cardholder data on local machines (cloud-only access)
- Clean desk policy
### 10. Track and Monitor All Access
**Requirement**: Log all access to network resources and cardholder data.
**What we did**:
- Centralized logging: ELK stack (Elasticsearch, Logstash, Kibana)
- CloudTrail: All AWS API calls logged
- Application logs: Every DB query, API request, auth attempt
- Retention: 1 year minimum
**Critical logs**:
```javascript
// Every transaction logged
{
"event": "payment_processed",
"transaction_id": "txn_abc123",
"amount": 150000,
"currency": "IDR",
"user_id": "usr_xyz789",
"timestamp": "2025-12-10T14:30:00Z",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0...",
"status": "success"
}
```
**Alerting rules**:
- Failed login >5 attempts in 10 min → alert
- DB access outside business hours → alert
- High-value transaction (>$10K) → review
- Unusual IP location → flag for review
### 11. Regularly Test Security Systems
**Requirement**: Test security systems and processes regularly.
**What we do quarterly**:
- **Penetration testing**: Hired third-party ethical hackers ($8K/test)
- **Vulnerability scanning**: Automated weekly (Nessus)
- **Code review**: All PRs require security review
- **Disaster recovery drill**: Simulate breach, test response
**Example finding** (Q3 2025 pentest):
- Vulnerability: Rate limiting insufficient on password reset
- Risk: Brute force attack possible
- Fix: Implemented exponential backoff + CAPTCHA
- Time to fix: 72 hours
### 12. Maintain Information Security Policy
**Requirement**: Security policy that addresses information security for all personnel.
**What we created**:
- 45-page security policy document
- Annual security training for all employees (mandatory)
- Incident response playbook
- Data breach notification procedure (72-hour disclosure)
**Policy highlights**:
- Password requirements: 16+ chars, special chars, no reuse
- Email phishing simulations: Monthly tests
- Clean desk policy: No printed cardholder data
- Data classification: Public, Internal, Confidential, Restricted
## The Audit Process
**Pre-audit preparation** (Month 5-6):
- Self-assessment questionnaire (SAQ): 300+ questions
- Evidence collection: Screenshots, logs, policies
- Gap remediation: Fix any remaining issues
**Audit week**:
- Day 1: Kickoff, document review
- Day 2-3: Technical testing, interviews
- Day 4: Findings review
- Day 5: Final report
**Our findings**:
- 2 minor issues (fixed same day)
- 0 major issues
- Result: **Certification achieved** ✅
## Ongoing Compliance (Post-Certification)
Certification isn't one-and-done. Ongoing requirements:
**Quarterly**:
- Vulnerability scans (Approved Scanning Vendor)
- Security policy review
- Access control audit
**Annually**:
- Full PCI-DSS re-assessment
- Penetration testing
- Employee security training refresh
**Cost**: $3K/month (scanning + monitoring tools)
## Common Pitfalls & How to Avoid
### Pitfall 1: Treating PCI as Checkbox Exercise
Many companies rush through compliance without understanding WHY.
**Fix**: Security-first mindset. PCI is minimum; go beyond it.
### Pitfall 2: Neglecting Vendor Compliance
If you use third-party services (payment gateway, cloud hosting), they must be PCI compliant too.
**Fix**: Verify vendor certifications (AOC - Attestation of Compliance)
### Pitfall 3: Lack of Documentation
Auditors need proof, not promises.
**Fix**: Document everything: policies, procedures, change logs, training records
### Pitfall 4: Over-Scoping CDE
The more systems in Cardholder Data Environment, the harder (and costlier) compliance becomes.
**Fix**: Minimize CDE. Use tokenization to reduce scope dramatically.
## Total Cost of PCI-DSS Compliance
**One-time**:
- QSA audit: $25K
- Security consulting: $30K
- Implementation (engineering time): $30K
**Total**: $85K
**Recurring**:
- Quarterly scans: $1K
- Security tools: $2K/month
- Annual re-audit: $15K
**Total**: ~$40K/year
**ROI**: Customer trust, legal protection, ability to process payments. Worth every dollar.
## Key Takeaways
1. **Start early**: Don't wait until you need certification. Build security in from day 1.
2. **Use tokenization**: Never store card numbers. Let Stripe/Xendit handle it.
3. **Automate compliance**: Manual processes don't scale. Automate scans, patches, monitoring.
4. **Document religiously**: If it's not documented, it didn't happen (in auditor's eyes).
5. **Continuous improvement**: Compliance is a journey, not a destination.
PCI-DSS is challenging but achievable. With the right approach, tools, and mindset, you can build a secure, compliant payment platform that earns customer trust.
When building a payment platform processing $50M+ annually, compliance isn't optional—it's existential. Here's our complete PCI-DSS certification journey and practical implementation guide.
## What is PCI-DSS and Why It Matters
**PCI-DSS** (Payment Card Industry Data Security Standard) is a set of security standards ensuring all companies that accept, process, store or transmit credit card information maintain a secure environment.
**Why you need it**:
- Legal requirement for processing card payments
- Customers won't trust you without it
- Penalties for breach: $5K-100K per month + lawsuits
- Reputational damage is often unrecoverable
**Our Timeline**:
- Month 1-2: Gap assessment & planning
- Month 3-5: Implementation & remediation
- Month 6: QSA audit
- Month 7: Certification achieved ✅
**Cost**: $85K (security tools + consulting + audit fees)
## The 12 PCI-DSS Requirements (and How We Implemented)
### 1. Install and Maintain Firewall Configuration
**Requirement**: Protect cardholder data with firewalls.
**What we did**:
- AWS Security Groups: Whitelist only necessary IPs/ports
- Web Application Firewall (WAF): CloudFlare for DDoS protection
- Network segmentation: Cardholder Data Environment (CDE) isolated from other systems
**Implementation**:
```yaml
# AWS Security Group (Payment Service)
Inbound Rules:
- Port 443 (HTTPS): From API Gateway only
- Port 5432 (PostgreSQL): From App Server only
- SSH (22): From VPN only (specific IP ranges)
Outbound Rules:
- Port 443: To payment gateways only
- All other ports: Denied by default
```
**Cost**: $2K/month (CloudFlare Enterprise + AWS)
### 2. Don't Use Vendor-Supplied Defaults
**Requirement**: Change default passwords and remove unnecessary default accounts.
**What we did**:
- All servers provisioned with unique SSH keys (no passwords)
- Database admin usernames changed from "admin" to randomized
- Default ports changed (PostgreSQL from 5432 → 15432)
- All default accounts disabled
**Automated Check**:
```bash
# Script runs daily via cron
#!/bin/bash
# Check for default usernames
forbidden_users=("admin" "root" "postgres" "mysql")
for user in "${forbidden_users[@]}"; do
if id "$user" &>/dev/null; then
alert_security_team "Default user $user exists"
fi
done
```
### 3. Protect Stored Cardholder Data
**Requirement**: Encrypt cardholder data at rest.
**Critical**: We **never store full card numbers**. Instead, we use tokenization via Stripe/Xendit.
**Data Flow**:
```
User enters card → Frontend sends to Stripe → Stripe returns token
→ We store token only (useless if stolen)
```
**For PII we must store** (name, email, transaction amounts):
```javascript
// Encryption at rest using AES-256
const encryptPII = (data) => {
const cipher = crypto.createCipheriv(
'aes-256-gcm',
KEY_FROM_AWS_KMS, // Rotation policy: 90 days
IV
);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
};
```
**Database encryption**: AWS RDS encrypted volumes (AES-256)
**Key management**: AWS KMS with automatic rotation every 90 days
### 4. Encrypt Transmission of Cardholder Data
**Requirement**: Encrypt cardholder data across public networks.
**What we did**:
- TLS 1.3 for all API endpoints (no TLS 1.0/1.1 allowed)
- Certificate pinning in mobile apps
- HSTS header: Force HTTPS always
- HTTP → HTTPS redirect at load balancer
**nginx config**:
```nginx
server {
listen 443 ssl http2;
# Strong TLS config
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
# HSTS: Force HTTPS for 1 year
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
```
**Testing**: Monthly SSL Labs scan (Grade A+ required)
### 5. Use and Regularly Update Anti-Virus
**Requirement**: Protect systems against malware.
**What we did**:
- ClamAV on all servers (open-source antivirus)
- File upload scanning before storage
- Daily definition updates
- Weekly full system scans
**Automated scanning**:
```bash
# Scan all uploaded files
for file in /uploads/*; do
clamscan "$file"
if [ $? -ne 0 ]; then
rm "$file"
alert_security_team "Malware detected: $file"
fi
done
```
### 6. Develop and Maintain Secure Systems
**Requirement**: All systems and applications must be free from known vulnerabilities.
**What we did**:
- Monthly dependency audits: `npm audit`, `bundle audit`
- Automated patching for OS (AWS Systems Manager)
- Quarterly penetration testing by third-party
- Bug bounty program ($500-$5K per valid vulnerability)
**CI/CD Security Checks**:
```yaml
# GitLab CI pipeline
security_scan:
script:
- npm audit --audit-level=high # Fail on high/critical
- snyk test --severity-threshold=high
- trivy image --severity HIGH,CRITICAL
```
**Result**: Average time to patch critical vulnerabilities: 48 hours
### 7. Restrict Access to Cardholder Data
**Requirement**: Limit access to cardholder data on "need to know" basis.
**What we did**:
- Role-Based Access Control (RBAC)
- Only 3 engineers have production DB access (encrypted, logged)
- MFA required for all system access
- Principle of least privilege
**Access Levels**:
```
Level 1 (Dev): Read access to non-PII data
Level 2 (Senior Dev): Read access to masked PII
Level 3 (Lead/DevOps): Full access, all actions logged
Level 4 (Auditor): Read-only access to everything
```
**Audit Log** (every access logged):
```json
{
"timestamp": "2025-12-10T14:23:11Z",
"user": "dan.ramdani@danlabs.co",
"action": "SELECT",
"table": "transactions",
"ip": "203.0.113.42",
"mfa_verified": true
}
```
### 8. Assign Unique ID to Each Person
**Requirement**: Each user must have unique credentials.
**What we did**:
- No shared accounts (each engineer has their own)
- SSO via Google Workspace
- MFA enforced (Authy/Google Authenticator)
- Session timeout: 15 minutes idle, 8 hours max
**MFA Implementation**:
```javascript
// Login requires password + TOTP code
const login = async (email, password, totpCode) => {
const user = await verifyPassword(email, password);
if (!user) throw new Error('Invalid credentials');
const totpValid = speakeasy.totp.verify({
secret: user.mfaSecret,
encoding: 'base32',
token: totpCode,
window: 1 // Allow 30-second clock skew
});
if (!totpValid) throw new Error('Invalid MFA code');
return generateJWT(user);
};
```
### 9. Restrict Physical Access
**Requirement**: Restrict physical access to cardholder data.
**What we did** (cloud-only infrastructure):
- AWS data centers (SOC 2 certified)
- No on-premise servers
- Physical access controls managed by AWS
- Office network isolated from production
**For office**:
- Disk encryption on all laptops (BitLocker/FileVault)
- No cardholder data on local machines (cloud-only access)
- Clean desk policy
### 10. Track and Monitor All Access
**Requirement**: Log all access to network resources and cardholder data.
**What we did**:
- Centralized logging: ELK stack (Elasticsearch, Logstash, Kibana)
- CloudTrail: All AWS API calls logged
- Application logs: Every DB query, API request, auth attempt
- Retention: 1 year minimum
**Critical logs**:
```javascript
// Every transaction logged
{
"event": "payment_processed",
"transaction_id": "txn_abc123",
"amount": 150000,
"currency": "IDR",
"user_id": "usr_xyz789",
"timestamp": "2025-12-10T14:30:00Z",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0...",
"status": "success"
}
```
**Alerting rules**:
- Failed login >5 attempts in 10 min → alert
- DB access outside business hours → alert
- High-value transaction (>$10K) → review
- Unusual IP location → flag for review
### 11. Regularly Test Security Systems
**Requirement**: Test security systems and processes regularly.
**What we do quarterly**:
- **Penetration testing**: Hired third-party ethical hackers ($8K/test)
- **Vulnerability scanning**: Automated weekly (Nessus)
- **Code review**: All PRs require security review
- **Disaster recovery drill**: Simulate breach, test response
**Example finding** (Q3 2025 pentest):
- Vulnerability: Rate limiting insufficient on password reset
- Risk: Brute force attack possible
- Fix: Implemented exponential backoff + CAPTCHA
- Time to fix: 72 hours
### 12. Maintain Information Security Policy
**Requirement**: Security policy that addresses information security for all personnel.
**What we created**:
- 45-page security policy document
- Annual security training for all employees (mandatory)
- Incident response playbook
- Data breach notification procedure (72-hour disclosure)
**Policy highlights**:
- Password requirements: 16+ chars, special chars, no reuse
- Email phishing simulations: Monthly tests
- Clean desk policy: No printed cardholder data
- Data classification: Public, Internal, Confidential, Restricted
## The Audit Process
**Pre-audit preparation** (Month 5-6):
- Self-assessment questionnaire (SAQ): 300+ questions
- Evidence collection: Screenshots, logs, policies
- Gap remediation: Fix any remaining issues
**Audit week**:
- Day 1: Kickoff, document review
- Day 2-3: Technical testing, interviews
- Day 4: Findings review
- Day 5: Final report
**Our findings**:
- 2 minor issues (fixed same day)
- 0 major issues
- Result: **Certification achieved** ✅
## Ongoing Compliance (Post-Certification)
Certification isn't one-and-done. Ongoing requirements:
**Quarterly**:
- Vulnerability scans (Approved Scanning Vendor)
- Security policy review
- Access control audit
**Annually**:
- Full PCI-DSS re-assessment
- Penetration testing
- Employee security training refresh
**Cost**: $3K/month (scanning + monitoring tools)
## Common Pitfalls & How to Avoid
### Pitfall 1: Treating PCI as Checkbox Exercise
Many companies rush through compliance without understanding WHY.
**Fix**: Security-first mindset. PCI is minimum; go beyond it.
### Pitfall 2: Neglecting Vendor Compliance
If you use third-party services (payment gateway, cloud hosting), they must be PCI compliant too.
**Fix**: Verify vendor certifications (AOC - Attestation of Compliance)
### Pitfall 3: Lack of Documentation
Auditors need proof, not promises.
**Fix**: Document everything: policies, procedures, change logs, training records
### Pitfall 4: Over-Scoping CDE
The more systems in Cardholder Data Environment, the harder (and costlier) compliance becomes.
**Fix**: Minimize CDE. Use tokenization to reduce scope dramatically.
## Total Cost of PCI-DSS Compliance
**One-time**:
- QSA audit: $25K
- Security consulting: $30K
- Implementation (engineering time): $30K
**Total**: $85K
**Recurring**:
- Quarterly scans: $1K
- Security tools: $2K/month
- Annual re-audit: $15K
**Total**: ~$40K/year
**ROI**: Customer trust, legal protection, ability to process payments. Worth every dollar.
## Key Takeaways
1. **Start early**: Don't wait until you need certification. Build security in from day 1.
2. **Use tokenization**: Never store card numbers. Let Stripe/Xendit handle it.
3. **Automate compliance**: Manual processes don't scale. Automate scans, patches, monitoring.
4. **Document religiously**: If it's not documented, it didn't happen (in auditor's eyes).
5. **Continuous improvement**: Compliance is a journey, not a destination.
PCI-DSS is challenging but achievable. With the right approach, tools, and mindset, you can build a secure, compliant payment platform that earns customer trust.
#fintech#compliance#PCI-DSS#security#payment processing#regulations
Related articles
Keep exploring Insights
Handpicked reads based on this topic.
Related Articles

Media Strategy
TikTok Marketing for Businesses in 2026: Beyond Dance Videos
TikTok isn't just for Gen Z anymore. B2B companies are getting 10x cheaper leads than LinkedIn. Here's the exact content framework that works.
•6 min read

Media Strategy
Facebook Ads vs Google Ads: Which Gets Better ROI for Your Business?
We spent $500K across both platforms for 30+ clients. Here's the data on which platform works better for different business types.
•7 min read

Business Insights
LinkedIn Ads for B2B: How to Generate Quality Leads (Not Just Clicks)
LinkedIn CPCs are 3x higher than Facebook. But for B2B, the lead quality is worth it. Here's our proven campaign structure.
•8 min read