Skip to main content

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 assessors 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.
endpoint inventory - payments148 routes

148 routes discovered (FastAPI, Flask). 11 reachable without authentication. Showing 6.

Discovered HTTP routes with handler location, authentication state and finding count.
MethodPathSubprojectHandlerAuthFindings
POST/api/v1/charges-services/payments/charge.py:142authenticatedCRIT1
POST/api/v1/charges/{id}/refund-services/payments/refund.py:88anonymousHIGH2
GET/api/v1/transactions/{id}-services/ledger/lookup.py:37authenticatedHIGH1
POST/api/v1/payouts-services/ledger/payout.py:54authenticatedMED1
POST/webhooks/acquirer-routes/webhooks.py:29unknownMED1
GET/internal/reconciliation/export-ops/reconcile.py:203anonymousHIGH1
Unknown means the handler runs behind a guard Vulkro could not resolve to a session check. It is listed, not scored.
The money-moving routes as the inventory prints them. Two of these reach the ledger without proving the caller owns the transaction, and one export is reachable with no session at all.

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.

compliance pack - pci-dss-4-032 controls, control-by-control page written
ControlWhat it asks forStatus
6.2.3Bespoke and custom software is reviewed prior to release to identify and correct potential coding vulnerabilitiesFail
6.2.4Software engineering techniques are in use to prevent or mitigate common software attacksFail
6.3.2An inventory of bespoke and custom software and third-party components is maintainedPartial
12.3.3Cryptographic cipher suites and protocols in use are documented and reviewed at least once every 12 monthsPartial
Four rows from the control page. Each control names the findings that support the assertion and the findings that contradict it, so the reviewer knows what to triage first.

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.

console - project overviewpayments-api
Health
71/10011 more findings than the previous scan

1 critical, 5 high, 9 medium148 endpointslast scan this build

Deploy gate: fail1 critical (max 0)
The release check as the pipeline reports it: what was found, how it moved since the last build, and the rule the gate applied to reach its verdict.

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.

The reviewVulkro

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.

You get: what to fix, and a pass or fail on the releaseWhat it checks
 Vulkro for Salesforce

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.

You get: a straight answer on whether you are ready to submitVulkro for Salesforce
The red teamVulkro RedComing soon

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.

You get: the attack, step by step, before someone else runs itHow it works

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.