Fintech and PCI DSS
Card assessment evidence, without widening your scope.
A card assessment is an argument about boundaries: what is inside the cardholder data environment, what can affect it, and what you can prove about both. A code review tool that takes a copy of the software behind that environment adds a boundary to the argument. Vulkro runs where the code already sits and writes its output in the clause numbering your assessor reads.
- PCI DSS 4.0, per control
- Requirements 6, 11 and 12
- Card data paths in code
- No copy of your code is taken
01 / Scope
A review tool can quietly become part of the assessment
Everything that stores, processes or transmits account data is in scope, and so is anything that can affect the security of it. That second clause is where tooling ends up.
Requirement 12.5.2 asks you to document and confirm your scope at least once a year, covering all the places account data flows. Every system that holds a copy of the software behind the cardholder data environment is a line in that document and a question at the assessment: where does it run, who administers it, what does it retain, and for how long. Adding a service that ingests your source is a small purchase with a permanent annual cost attached.
Vulkro does not create that copy. The review runs on the machine that already holds the code, or on the build runner that already checks it out, and the findings, the reports and the evidence pack are written next to it. There is no vendor environment holding your software, which means there is nothing new for your scope document to describe. Whether any given system is in or out of scope is your assessor’s determination, and this is one they can make quickly.
It also removes the residency argument. The analysis happens wherever the machine is, so a workload that has to stay in one jurisdiction stays there, with no contract addendum about where a scan was processed.
02 / Account data in code
Where card data actually turns up
The database is the part everybody has already thought about. These are the six places a card assessment finds account data that nobody meant to leave there.
- Card numbers written into the source
- Digit runs that pass the card check-digit test, wherever they sit: a fixture, a seed migration, a comment, a sample payload. Some are test numbers that belong in a test-only file, and some are a real customer’s card pasted in during a debugging session two years ago. Both are in your version control history until somebody looks.
- Live payment keys in the repository
- Payment platform keys are recognised by the published prefix shapes their issuers document, and a live credential is separated from a test one. A signing secret for an inbound webhook is treated separately from a client key, because the failure mode is a forged callback rather than a stolen key.
- Cryptography on stored account data
- Obsolete hashes and ciphers on paths that carry card data, block modes that leak structure, keys and initialisation vectors written into the source, transport settings that still accept retired protocol versions, and nonces drawn from a random source that was never meant to be unpredictable.
- Authorisation on the money-moving routes
- Charge, refund, payout, transaction lookup and reconciliation export. The recurring failure is not a missing login: it is a route that proves the caller is signed in and never proves the transaction is theirs, sitting next to sibling routes that do check.
- Injection on the transaction paths
- A value from the request reaching a query, a command or a template on a path that touches the ledger. The finding names the file, the line and the route it arrived through, so the fix and the evidence are the same artifact.
- The components underneath
- The dependency inventory and the advisories against it, matched against a database on your disk. Requirement 6.3.2 asks for exactly this inventory, and it is the one most teams assemble by hand the week before an assessment.
148 routes discovered (FastAPI, Flask). 11 reachable without authentication. Showing 6.
| Method | Path | Subproject | Handler | Auth | Findings |
|---|---|---|---|---|---|
| POST | /api/v1/charges | - | services/payments/charge.py:142 | authenticated | CRIT1 |
| POST | /api/v1/charges/{id}/refund | - | services/payments/refund.py:88 | anonymous | HIGH2 |
| GET | /api/v1/transactions/{id} | - | services/ledger/lookup.py:37 | authenticated | HIGH1 |
| POST | /api/v1/payouts | - | services/ledger/payout.py:54 | authenticated | MED1 |
| POST | /webhooks/acquirer | - | routes/webhooks.py:29 | unknown | MED1 |
| GET | /internal/reconciliation/export | - | ops/reconcile.py:203 | anonymous | HIGH1 |
| Unknown means the handler runs behind a guard Vulkro could not resolve to a session check. It is listed, not scored. | |||||
The inventory comes first for a reason. A route that was never mapped is a route no rule ran against, so an assessment that starts from a finding list without an endpoint list is starting from an unknown denominator.
03 / The control map
PCI DSS 4.0, control by control
The card framework is the deepest mapping in the product. About thirty controls across Requirements 6, 11 and 12, each with its published title, a plain statement of what it asks for, and the evidence for and against it from your own scan.
| Control | What it asks for | Status |
|---|---|---|
| 6.2.3 | Bespoke and custom software is reviewed prior to release to identify and correct potential coding vulnerabilities | Fail |
| 6.2.4 | Software engineering techniques are in use to prevent or mitigate common software attacks | Fail |
| 6.3.2 | An inventory of bespoke and custom software and third-party components is maintained | Partial |
| 12.3.3 | Cryptographic cipher suites and protocols in use are documented and reviewed at least once every 12 months | Partial |
Two things make this worth more than a finding list with a clause number stapled on. The first is that each row states what the control requires before it shows you anything, so a reviewer who does not know your codebase can still follow the assertion. The second is the column for evidence that contradicts the control: an assessor wants to know which findings undercut the claim you are making, and putting that next to the claim is faster than making them derive it.
Requirement 12.3.3 is the clearest example of the mapping paying for itself. It asks you to document the cipher suites and protocols in use and review them annually, which is a question about your code that most teams answer from memory. The scan answers it from the code, and the answer lands in the row that asks for it.
04 / Cadence
Proving you run it again, not just that you ran it once
Requirement 6.2.3 asks for a review before release and 6.4.1 asks for public-facing applications to be reviewed after any significant change. Both are about repetition, which is a harder thing to evidence than a single result.
The review runs in the pipeline that already builds the release. A build fails when a newly introduced high-risk finding appears, while the backlog you started with burns down on its own schedule rather than blocking every merge on day one. That distinction is what keeps the check switched on: a gate that fails the whole team on inherited debt gets disabled in a week, and then nothing is gated at all.
It stays trustworthy because the result is repeatable. The same code, the same version of the scanner and the same settings produce the same result, so a difference between two builds is a change in your software rather than a change in the tool. That is also what turns a quarter of scans into an evidence trail: dated results that can be laid beside each other.
1 critical, 5 high, 9 medium148 endpointslast scan this build
Everything else about audit evidence is shared with the other regulated sectors and lives one level up: what an auditor asks for, which frameworks are mapped, and why none of it requires sending your code anywhere. The full PCI control mapping is in the compliance docs, and the pipeline setup is on the continuous integration page.
The review, and the red team
Vulkro reviews your codebase. Vulkro for Salesforce reviews your Salesforce build, which is where a lot of financial services runs: Financial Services Cloud, the org settings behind it, and the data bridged out of it. Vulkro Red is the other half of the team, taking what the review found and working out which small problems chain into a real break-in.
Reviews your code
Goes through every line of your codebase before a release, the way a senior engineer would if they had the time, and tells you what a customer could exploit.
Reviews your Salesforce build
The same review for the part of your business that runs on Salesforce, including the settings in the org itself, and what the AppExchange security review will ask you for.
Attacks what they found
Takes the review and works out what an attacker would actually do with it: which small problems chain together into a real break-in, and which ones are noise.
One engine behind all three, so the red team works from what the review already foundIt all runs on your machine. Your code never leaves it.