Pci Compliance
Unverified●30/40Claude Code◐PartialHas SKILL.md but declares no allowed-tools — Claude Code will ask for permission each time
Cursor◐PartialPlain prose you can paste in — but no Cursor rules file
Codex◐PartialPlain prose you can paste in — but no AGENTS.md
Gemini CLI◐PartialPlain prose you can paste in
Copilot◐PartialPlain prose you can paste in — but no Copilot instructions file
npx agentalley add pci-complianceWho is stuck, and on what
Implement PCI DSS compliance requirements for secure handling of payment card data and payment systems. Use when securing payment processing, achieving PCI compliance, or implementing payment card security measures.
The whole source
Frontmatter — 2 properties
| name | pci-compliance |
|---|---|
| description | Implement PCI DSS compliance requirements for secure handling of payment card data and payment systems. Use when securing payment processing, achieving PCI compliance, or implementing payment card security measures. |
| 1 | --- |
| 2 | name: pci-compliance |
| 3 | description: Implement PCI DSS compliance requirements for secure handling of payment card data and payment systems. Use when securing payment processing, achieving PCI compliance, or implementing payment card security measures. |
| 4 | ---A5 — No allowed-tools declared — no way to tell what this skill may touch |
| 5 | |
| 6 | # PCI Compliance |
| 7 | |
| 8 | Master PCI DSS (Payment Card Industry Data Security Standard) compliance for secure payment processing and handling of cardholder data. |
| 9 | |
| 10 | ## When to Use This Skill |
| 11 | |
| 12 | - Building payment processing systems |
| 13 | - Handling credit card information |
| 14 | - Implementing secure payment flows |
| 15 | - Conducting PCI compliance audits |
| 16 | - Reducing PCI compliance scope |
| 17 | - Implementing tokenization and encryption |
| 18 | - Preparing for PCI DSS assessments |
| 19 | |
| 20 | ## PCI DSS Requirements (12 Core Requirements) |
| 21 | |
| 22 | ### Build and Maintain Secure Network |
| 23 | |
| 24 | 1. Install and maintain firewall configuration |
| 25 | 2. Don't use vendor-supplied defaults for passwords |
| 26 | |
| 27 | ### Protect Cardholder Data |
| 28 | |
| 29 | 3. Protect stored cardholder data |
| 30 | 4. Encrypt transmission of cardholder data across public networks |
| 31 | |
| 32 | ### Maintain Vulnerability Management |
| 33 | |
| 34 | 5. Protect systems against malware |
| 35 | 6. Develop and maintain secure systems and applications |
| 36 | |
| 37 | ### Implement Strong Access Control |
| 38 | |
| 39 | 7. Restrict access to cardholder data by business need-to-know |
| 40 | 8. Identify and authenticate access to system components |
| 41 | 9. Restrict physical access to cardholder data |
| 42 | |
| 43 | ### Monitor and Test Networks |
| 44 | |
| 45 | 10. Track and monitor all access to network resources and cardholder data |
| 46 | 11. Regularly test security systems and processes |
| 47 | |
| 48 | ### Maintain Information Security Policy |
| 49 | |
| 50 | 12. Maintain a policy that addresses information security |
| 51 | |
| 52 | ## Compliance Levels |
| 53 | |
| 54 | **Level 1**: > 6 million transactions/year (annual ROC required) |
| 55 | **Level 2**: 1-6 million transactions/year (annual SAQ) |
| 56 | **Level 3**: 20,000-1 million e-commerce transactions/year |
| 57 | **Level 4**: < 20,000 e-commerce or < 1 million total transactions |
| 58 | |
| 59 | ## Data Minimization (Never Store) |
| 60 | |
| 61 | ```python |
| 62 | # NEVER STORE THESE |
| 63 | PROHIBITED_DATA = { |
| 64 | 'full_track_data': 'Magnetic stripe data', |
| 65 | 'cvv': 'Card verification code/value', |
| 66 | 'pin': 'PIN or PIN block' |
| 67 | } |
| 68 | |
| 69 | # CAN STORE (if encrypted) |
| 70 | ALLOWED_DATA = { |
| 71 | 'pan': 'Primary Account Number (card number)', |
| 72 | 'cardholder_name': 'Name on card', |
| 73 | 'expiration_date': 'Card expiration', |
| 74 | 'service_code': 'Service code' |
| 75 | } |
| 76 | |
| 77 | class PaymentData: |
| 78 | """Safe payment data handling.""" |
| 79 | |
| 80 | def __init__(self): |
| 81 | self.prohibited_fields = ['cvv', 'cvv2', 'cvc', 'pin'] |
| 82 | |
| 83 | def sanitize_log(self, data): |
| 84 | """Remove sensitive data from logs.""" |
| 85 | sanitized = data.copy() |
| 86 | |
| 87 | # Mask PAN |
| 88 | if 'card_number' in sanitized: |
| 89 | card = sanitized['card_number'] |
| 90 | sanitized['card_number'] = f"{card[:6]}{'*' * (len(card) - 10)}{card[-4:]}" |
| 91 | |
| 92 | # Remove prohibited data |
| 93 | for field in self.prohibited_fields: |
| 94 | sanitized.pop(field, None) |
| 95 | |
| 96 | return sanitized |
| 97 | |
| 98 | def validate_no_prohibited_storage(self, data): |
| 99 | """Ensure no prohibited data is being stored.""" |
| 100 | for field in self.prohibited_fields: |
| 101 | if field in data: |
| 102 | raise SecurityError(f"Attempting to store prohibited field: {field}") |
| 103 | ``` |
| 104 | |
| 105 | ## Tokenization |
| 106 | |
| 107 | ### Using Payment Processor Tokens |
| 108 | |
| 109 | ```python |
| 110 | import stripe |
| 111 | |
| 112 | class TokenizedPayment: |
| 113 | """Handle payments using tokens (no card data on server).""" |
| 114 | |
| 115 | @staticmethod |
| 116 | def create_payment_method_token(card_details): |
| 117 | """Create token from card details (client-side only).""" |
| 118 | # THIS SHOULD ONLY BE DONE CLIENT-SIDE WITH STRIPE.JS |
| 119 | # NEVER send card details to your server |
| 120 | |
| 121 | """ |
| 122 | // Frontend JavaScript |
| 123 | const stripe = Stripe('pk_...'); |
| 124 | |
| 125 | const {token, error} = await stripe.createToken({ |
| 126 | card: { |
| 127 | number: '4242424242424242', |
| 128 | exp_month: 12, |
| 129 | exp_year: 2024, |
| 130 | cvc: '123' |
| 131 | } |
| 132 | }); |
| 133 | |
| 134 | // Send token.id to server (NOT card details) |
| 135 | """ |
| 136 | pass |
| 137 | |
| 138 | @staticmethod |
| 139 | def charge_with_token(token_id, amount): |
| 140 | """Charge using token (server-side).""" |
| 141 | # Your server only sees the token, never the card number |
| 142 | stripe.api_key = "sk_..." |
| 143 | |
| 144 | charge = stripe.Charge.create( |
| 145 | amount=amount, |
| 146 | currency="usd", |
| 147 | source=token_id, # Token instead of card details |
| 148 | description="Payment" |
| 149 | ) |
| 150 | |
| 151 | return charge |
| 152 | |
| 153 | @staticmethod |
| 154 | def store_payment_method(customer_id, payment_method_token): |
| 155 | """Store payment method as token for future use.""" |
| 156 | stripe.Customer.modify( |
| 157 | customer_id, |
| 158 | source=payment_method_token |
| 159 | ) |
| 160 | |
| 161 | # Store only customer_id and payment_method_id in your database |
| 162 | # NEVER store actual card details |
| 163 | return { |
| 164 | 'customer_id': customer_id, |
| 165 | 'has_payment_method': True |
| 166 | # DO NOT store: card number, CVV, etc. |
| 167 | } |
| 168 | ``` |
| 169 | |
| 170 | ### Custom Tokenization (Advanced) |
| 171 | |
| 172 | ```python |
| 173 | import secrets |
| 174 | from cryptography.fernet import Fernet |
| 175 | |
| 176 | class TokenVault: |
| 177 | """Secure token vault for card data (if you must store it).""" |
| 178 | |
| 179 | def __init__(self, encryption_key): |
| 180 | self.cipher = Fernet(encryption_key) |
| 181 | self.vault = {} # In production: use encrypted database |
| 182 | |
| 183 | def tokenize(self, card_data): |
| 184 | """Convert card data to token.""" |
| 185 | # Generate secure random token |
| 186 | token = secrets.token_urlsafe(32) |
| 187 | |
| 188 | # Encrypt card data |
| 189 | encrypted = self.cipher.encrypt(json.dumps(card_data).encode()) |
| 190 | |
| 191 | # Store token -> encrypted data mapping |
| 192 | self.vault[token] = encrypted |
| 193 | |
| 194 | return token |
| 195 | |
| 196 | def detokenize(self, token): |
| 197 | """Retrieve card data from token.""" |
| 198 | encrypted = self.vault.get(token) |
| 199 | if not encrypted: |
| 200 | raise ValueError("Token not found") |
| 201 | |
| 202 | # Decrypt |
| 203 | decrypted = self.cipher.decrypt(encrypted) |
| 204 | return json.loads(decrypted.decode()) |
| 205 | |
| 206 | def delete_token(self, token): |
| 207 | """Remove token from vault.""" |
| 208 | self.vault.pop(token, None) |
| 209 | ``` |
| 210 | |
| 211 | ## Encryption |
| 212 | |
| 213 | ### Data at Rest |
| 214 | |
| 215 | ```python |
| 216 | from cryptography.hazmat.primitives.ciphers.aead import AESGCM |
| 217 | import os |
| 218 | |
| 219 | class EncryptedStorage: |
| 220 | """Encrypt data at rest using AES-256-GCM.""" |
| 221 | |
| 222 | def __init__(self, encryption_key): |
| 223 | """Initialize with 256-bit key.""" |
| 224 | self.key = encryption_key # Must be 32 bytes |
| 225 | |
| 226 | def encrypt(self, plaintext): |
| 227 | """Encrypt data.""" |
| 228 | # Generate random nonce |
| 229 | nonce = os.urandom(12) |
| 230 | |
| 231 | # Encrypt |
| 232 | aesgcm = AESGCM(self.key) |
| 233 | ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None) |
| 234 | |
| 235 | # Return nonce + ciphertext |
| 236 | return nonce + ciphertext |
| 237 | |
| 238 | def decrypt(self, encrypted_data): |
| 239 | """Decrypt data.""" |
| 240 | # Extract nonce and ciphertext |
| 241 | nonce = encrypted_data[:12] |
| 242 | ciphertext = encrypted_data[12:] |
| 243 | |
| 244 | # Decrypt |
| 245 | aesgcm = AESGCM(self.key) |
| 246 | plaintext = aesgcm.decrypt(nonce, ciphertext, None) |
| 247 | |
| 248 | return plaintext.decode() |
| 249 | |
| 250 | # Usage |
| 251 | storage = EncryptedStorage(os.urandom(32)) |
| 252 | encrypted_pan = storage.encrypt("4242424242424242") |
| 253 | # Store encrypted_pan in database |
| 254 | ``` |
| 255 | |
| 256 | ### Data in Transit |
| 257 | |
| 258 | ```python |
| 259 | # Always use TLS 1.2 or higher |
| 260 | # Flask/Django example |
| 261 | app.config['SESSION_COOKIE_SECURE'] = True # HTTPS only |
| 262 | app.config['SESSION_COOKIE_HTTPONLY'] = True |
| 263 | app.config['SESSION_COOKIE_SAMESITE'] = 'Strict' |
| 264 | |
| 265 | # Enforce HTTPS |
| 266 | from flask_talisman import Talisman |
| 267 | Talisman(app, force_https=True) |
| 268 | ``` |
| 269 | |
| 270 | ## Additional patterns and templates |
| 271 | |
| 272 | More detailed templates and worked examples live in `references/details.md`. Read that file for the full pattern library. |
| 273 | |
| 274 |
Reviews
Installed this one?Write the first review and take the Trailblazer badge.
Alternatives
Structure Your Invention For A Patent FilingDescribe your invention in plain words and get back a formal write-up that lays out the problem it solves, how it works, and which parts are worth protecting.●····●37/40Claims Drafting: The Core Patent SkillDescribe your invention in plain words and get back a numbered set of formal patent claims — the legal wording that defines exactly what you own.●····●36/40Patent Novelty and Non-Obviousness CheckDescribe your invention in everyday words and get back a clear read on whether it's new and original enough to patent, plus where it might hit trouble.●····●35/40Patent Pipeline: From Invention to FilingDescribe your invention in plain words and get back a complete first-draft patent application — claims, full description, and abstract — ready to hand to a patent attorney.●····●35/40