payment-pci-security
Apply when handling credit card data, implementing secureProxyUrl flows, or working with payment security and proxy code. Covers PCI DSS compliance, Secure Proxy card tokenization, sensitive data handling rules, X-PROVIDER-Forward-To header usage, custom token creation, and the constraint that Secure Proxy applies only to card authorization (not post-auth operations like cancel, capture, or refund). Use for any payment connector that processes credit, debit, or co-branded card payments to prevent data breaches and PCI violations.
What this skill does
# PCI Compliance & Secure Proxy
## When this skill applies
Use this skill when:
- Building a payment connector that accepts credit cards, debit cards, or co-branded cards
- The connector needs to process card data or communicate with an acquirer
- Determining whether Secure Proxy is required for the hosting environment
- Auditing a connector for PCI DSS compliance (data storage, logging, transmission)
Do not use this skill for:
- PPP endpoint contracts and response shapes — use [`payment-provider-protocol`](../payment-provider-protocol/SKILL.md)
- Idempotency and duplicate prevention — use [`payment-idempotency`](../payment-idempotency/SKILL.md)
- Async payment flows (Boleto, Pix) and callbacks — use [`payment-async-flow`](../payment-async-flow/SKILL.md)
## Decision rules
- If the connector is hosted in a non-PCI environment (including all VTEX IO apps), it MUST use Secure Proxy.
- If the connector has PCI DSS certification (AOC signed by a QSA), it can call the acquirer directly with raw card data.
- Check for `secureProxyUrl` in the Create Payment request — if present, Secure Proxy is active and MUST be used.
- **`secureProxyUrl` is only present in the Create Payment (authorize) request.** Cancel, capture, settle, and refund operations do not carry card data and do not receive this field. Post-authorization calls go directly to the PSP API using credentials and `outbound-access` policies — this does not reduce PCI compliance because no card data is involved in those operations.
- Card tokens (`numberToken`, `holderToken`, `cscToken`) are only valid when sent through the `secureProxyUrl` — the proxy replaces them with real data before forwarding to the acquirer.
- Only `card.bin` (first 6 digits), `card.numberLength`, and `card.expiration` may be stored. Everything else is forbidden.
- Card data must never appear in logs, databases, files, caches, error trackers, or APM tools — even in development.
## Hard constraints
### Constraint: MUST use secureProxyUrl for non-PCI environments
If the connector is hosted in a non-PCI environment (including all VTEX IO apps), it MUST use the `secureProxyUrl` from the Create Payment request to communicate with the acquirer. It MUST NOT call the acquirer directly with raw card data. If a `secureProxyUrl` field is present in the request, Secure Proxy is active and MUST be used.
**Why this matters**
Non-PCI environments are not authorized to handle raw card data. Calling the acquirer directly bypasses the Gateway's secure data handling, violating PCI DSS. This can result in data breaches, massive fines ($100K+ per month), loss of card processing ability, and legal liability.
**Detection**
If the connector calls an acquirer endpoint directly (without going through `secureProxyUrl`) when `secureProxyUrl` is present in the request, STOP immediately. All acquirer communication must go through the Secure Proxy.
**Correct**
```typescript
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, secureProxyUrl, card } = req.body;
if (secureProxyUrl) {
// Non-PCI: Route through Secure Proxy
const acquirerResponse = await fetch(secureProxyUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-PROVIDER-Forward-To": "https://api.acquirer.com/v2/payments",
"X-PROVIDER-Forward-MerchantId": process.env.ACQUIRER_MERCHANT_ID!,
"X-PROVIDER-Forward-MerchantKey": process.env.ACQUIRER_MERCHANT_KEY!,
},
body: JSON.stringify({
orderId: paymentId,
payment: {
cardNumber: card.numberToken, // Token, not real number
holder: card.holderToken, // Token, not real name
securityCode: card.cscToken, // Token, not real CVV
expirationMonth: card.expiration.month,
expirationYear: card.expiration.year,
},
}),
});
const result = await acquirerResponse.json();
// Build and return PPP response...
}
}
```
**Wrong**
```typescript
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, secureProxyUrl, card } = req.body;
// WRONG: Calling acquirer directly, bypassing Secure Proxy
// This connector is non-PCI but handles card data as if it were PCI-certified
const acquirerResponse = await fetch("https://api.acquirer.com/v2/payments", {
method: "POST",
headers: {
"Content-Type": "application/json",
MerchantId: process.env.ACQUIRER_MERCHANT_ID!,
},
body: JSON.stringify({
orderId: paymentId,
payment: {
// These are tokens but sent directly to acquirer — acquirer can't read tokens!
// And if raw data were here, this would be a PCI violation
cardNumber: card.numberToken,
holder: card.holderToken,
securityCode: card.cscToken,
},
}),
});
// This request will fail: acquirer receives tokens instead of real card data
// And the Secure Proxy was completely bypassed
}
```
### Constraint: Secure Proxy applies ONLY to card authorization — not to post-auth operations
The `secureProxyUrl` field is present **only in the Create Payment request** (card authorization). Cancel, capture (settle), and refund requests do **not** include `secureProxyUrl` because they do not involve card data — they reference the transaction by `tid`, `authorizationId`, or `paymentId`.
Post-authorization calls MUST go directly to the PSP API using an `ExternalClient` with API credentials, authorized via `outbound-access` policies in `manifest.json`.
**Why this matters**
Attempting to route cancel/capture/refund through Secure Proxy will fail because `secureProxyUrl` is `undefined` in those requests. Architecturally, there is no PCI concern — only the authorization carries sensitive card data. Agents and developers who assume all PSP communication must go through Secure Proxy waste significant time debugging `undefined` proxy URLs.
**Detection**
If cancel, capture, or refund handlers reference `secureProxyUrl`, use `SecureExternalClient`, or attempt to route through Secure Proxy, STOP. Use `ExternalClient` with direct API calls for post-auth operations.
**Correct — two-client architecture**
```typescript
// Authorization (Create Payment) — via Secure Proxy
import { SecureExternalClient } from "@vtex/payment-provider";
export class PspSecureClient extends SecureExternalClient {
public async authorize(data: object, secureProxyUrl: string) {
return this.http.post("/payments", data, {
secureProxy: secureProxyUrl,
} as any);
}
}
// Cancel, Capture, Refund — direct API calls
import { ExternalClient } from "@vtex/api";
export class PspClient extends ExternalClient {
public async capture(tid: string, amount: number) {
return this.http.post(
`/payments/${tid}/capture`,
{ amount },
{
headers: { "X-API-Key": "..." },
},
);
}
}
```
**Wrong**
```typescript
// WRONG — trying to use SecureExternalClient for all operations
async settle(request: SettlementRequest) {
// secureProxyUrl does not exist on SettlementRequest — this is undefined
await this.secureClient.capture(request.tid, request.value, request.secureProxyUrl)
}
```
### Constraint: Headless storefront BFFs MUST NOT proxy card data to vtexpayments.com.br
In a headless storefront, the Send payments information call (`POST https://{account}.vtexpayments.com.br/api/pub/transactions/{tid}/payments`) MUST originate from the shopper's browser or native app. The merchant's BFF (Node, Next.js route handler, edge function, lambda, reverse proxy, or any server-side component) MUST NOT receive card fields from the browser and MUST NOT forward them to the Payment Gateway, even with redaction, even with `appKey`/`appToken` on the server side, and even when only "tokenized" fields appear to be forwarded.
This constraint extends the same PCI principle that drives Secure Proxy: a non-PCI envirRelated in Security
mac-ops
IncludedComprehensive macOS workstation operations — diagnose kernel panics, identify failing drives, audit launchd startup items, decode wake reasons, triage TCC permission denials, manage APFS snapshots, recover from no-boot. Use for: Mac is slow, slow bootup, won't boot, kernel panic, kernel_task hot, mds_stores CPU, photoanalysisd, cloudd, login loop, gray screen, sleep wake failure, drive failing, IO errors, APFS snapshots eating space, Time Machine local snapshots, Spotlight indexing, launchd, LaunchAgent, LaunchDaemon, login items, TCC permissions, Full Disk Access, Screen Recording denied, Gatekeeper, quarantine, com.apple.quarantine, app is damaged, helper tool, /Library/PrivilegedHelperTools, pmset, wake reasons, dark wake, sysdiagnose, panic.ips, DiagnosticReports, configuration profile, MDM profile, remote diagnostics over SSH.
a11y-audit
IncludedRun accessibility audits on web projects combining automated scanning (axe-core, Lighthouse) with WCAG 2.1 AA compliance mapping, manual check guidance, and structured reporting. Output is configurable: markdown report only, markdown plus machine-readable JSON, or markdown plus issue tracker integration. Use this skill whenever the user mentions "accessibility audit", "a11y audit", "WCAG audit", "accessibility check", "compliance scan", or asks to check a web project for accessibility issues. Also trigger when the user wants to verify WCAG conformance or map findings to a specific standard (CAN-ASC-6.2, EN 301 549, ADA/AODA).
erpclaw
IncludedAI-native ERP system with self-extending OS. Full accounting, invoicing, inventory, purchasing, tax, billing, HR, payroll, advanced accounting (ASC 606/842, intercompany, consolidation), and financial reporting. 413 actions across 14 domains, 43 expansion modules. Constitutional guardrails, adversarial audit, schema migration. Double-entry GL, immutable audit trail, US GAAP.
assess
IncludedAssesses and rates quality 0-10 across multiple dimensions (correctness, maintainability, security, performance, testability, simplicity) with pros/cons analysis. Compares against project conventions and prior decisions from memory. Produces structured evaluation reports with actionable improvement suggestions. Use when evaluating code, designs, architectures, or comparing alternative approaches.
spring-boot-security-jwt
IncludedProvides JWT authentication and authorization patterns for Spring Boot 3.5.x covering token generation with JJWT, Bearer/cookie authentication, database/OAuth2 integration, and RBAC/permission-based access control using Spring Security 6.x. Use when implementing authentication or authorization in Spring Boot applications.
code-hardcode-audit
IncludedDetect hardcoded values, magic numbers, and leaked secrets. TRIGGERS - hardcode audit, magic numbers, PLR2004, secret scanning.