Secure before you ship
Ship code your customers can trust.
Finds the bugs that turn into breaches and fixes them before they reach your customers. All of your code, checked on your machine, with nothing sent to the cloud.
- Completely offline
- Zero running cost
- No AI in the scan
- Deterministic
- Fixes are verified
- Air-gap ready
$ vulkro scan . [CRITICAL] SQL injection in order lookup checkout.py:214 CWE-89 VULK-1042 [HIGH] Missing authorization on invoice download routes/invoice.ts:47 CWE-639 VULK-2117 release gate: FAIL (1 critical, 1 high) exit 1
01 / The team
The security team you could not otherwise hire.
Two reviewers and a red team on one engine. The reviewers find what is wrong; the red team shows which problems actually matter.
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.
02 / The review: your code
Every line of your code, read before it ships.
Traces what a user can type all the way to your database, files, and commands, and shows the exact route, step by step.
| Severity | Finding | CWE | Rule |
|---|---|---|---|
| CRIT | SQL injection in order lookupcheckout.py:214 | CWE-89 | VULK-1042 |
Dataflow pathVULK-1042
4 hops resolved. No sanitiser between the source and the sink. | |||
| HIGH | Missing authorization on invoice downloadroutes/invoice.ts:47 | CWE-639 | VULK-2117 |
| HIGH | SSRF via user-supplied URLproxy-handler.ts:23 | CWE-918 | VULK-1180 |
| MED | Hardcoded API token committed to the repositoryconfig/stripe.js:9 | CWE-798 | VULK-3304 |
- OWASP API Top 10 and 180+ checks
- SQL, command, and template injection
- IDOR, CSRF, SSRF, XSS, mass assignment
- Cross-file taint with reachability
- Secrets in code and git history
- Dependency CVEs: npm, PyPI, Go, Cargo, Maven
- Containers and infrastructure-as-code
- SBOM (CycloneDX, SPDX) and VEX
- Compliance: SOC 2, PCI, HIPAA, GDPR, ISO 27001
- Python, JavaScript, TypeScript, Go, and Java
180+
Security checks
Deliberately understated
5
Languages with a live parser
Python, JavaScript, TypeScript, Go, Java
124
Secret provider rules
Working tree and git history
26
Output formats
Drift-tested against the docs
03 / The review: your Salesforce build
The same review, for the part of your business that runs on Salesforce.
The same review for what your team built on Salesforce, plus the org settings, read the way an AppExchange review reads them.
9 blocking gaps across 3 of 6 requirement categories. 1 category not evaluated.
- Package
- Acme Billing Suite
- Version
- 3.4.0
- Basis
- checklist pinned 2026-Q2
| Requirement category | Criterion | Status | Blocking | Highest | First citation |
|---|---|---|---|---|---|
| Secure coding and injection defence | SF-ASRR-001 | gap | 3 | CRIT | force-app/main/default/classes/InvoiceController.cls:214 builds SOQL from a page parameter. |
| Sensitive data protection and cryptography | SF-ASRR-002 | pass | 0 | none | No key, token or credential literal in package source or metadata. |
| Sharing and access control | SF-ASRR-003 | gap | 5 | HIGH | force-app/main/default/classes/QuoteService.cls:88 writes without a CRUD or FLS check. |
| Client-side and UI security | SF-ASRR-004 | gap | 1 | MED | force-app/main/default/lwc/quoteViewer/quoteViewer.js:63 assigns a record value to innerHTML. |
| Integrations and external callouts | SF-ASRR-005 | pass | 0 | none | Every callout routes through a Named Credential over TLS. |
| Least-privilege metadata and automation | SF-ASRR-006 | not evaluated | 0 | unknown | No profile or permission set metadata was retrieved in this scan, so nothing was scored. |
Readiness assessment against the published AppExchange Security Review requirements. It is not an official review outcome: Salesforce Product Security decides that. A category no detector covered on this scan reads not evaluated, does not block, and still needs checking by hand.
- Apex, with cross-method taint
- Lightning Web Components, Aura, Visualforce
- Flow and Process Builder
- Sharing, CRUD, and FLS enforcement
- Org posture: perms, MFA, sessions, sharing rules
- AppExchange Security Review readiness
- PII and PHI de-identification
- Named credentials and connected apps
- Metadata governance and unused-access bloat
- Live-org scanning
04 / How it works
Find, prove, fix, gate.
Four steps. The last one is a verdict you can put in front of a release and defend.
Find
Reads the source, maps every route, and follows user input into the places that trust it.
Prove
Each finding carries its hops, file and line. No evidence, no finding.
Fix
A local model drafts the patch. Applied only when a fresh scan agrees it is gone.
Gate
Findings over your threshold exit non-zero and stop the pipeline. Same commit, same verdict.
| Line before | Line after | Change | Source |
|---|---|---|---|
| @@ -3,3 +3,5 @@ | |||
| 3 | 3 | import {HttpError} from '../http/errors'; | |
| 4 | 4 | ||
| 5 | Added line. const ALLOWED_HOSTS = new Set(['assets.example.com', 'files.example.com']); | ||
| 6 | Added line. | ||
| 5 | 7 | const PROXY_TIMEOUT_MS = 5_000; | |
| @@ -18,6 +20,9 @@ export async function proxyHandler | |||
| 18 | 20 | export async function proxyHandler(req: Request, res: Response) { | |
| 19 | Removed line. const target = req.query.url as string; | ||
| 20 | Removed line. const upstream = await fetch(target); | ||
| 21 | Added line. const target = new URL(String(req.query.url)); | ||
| 22 | Added line. if (!ALLOWED_HOSTS.has(target.hostname)) { | ||
| 23 | Added line. throw new HttpError(400, `blocked upstream host: ${target.hostname}`); | ||
| 24 | Added line. } | ||
| 25 | Added line. const upstream = await fetch(target.href); | ||
| 21 | 26 | ||
| 22 | 27 | res.status(upstream.status).send(await upstream.text()); | |
| 23 | 28 | } | |
05 / The proof
We publish the misses too.
Tested on real apps with known bugs. We publish the misses too.
| Result | |
|---|---|
| Real vulnerabilities found | 54 of 83 |
| Vulnerabilities it missed | 29 |
| False alarms | 9 |
| Of everything it flagged, how much was real | 86% |
| Time to scan every application | 41.7s |
Measured on vulkro 0.22.0, 2026-08-28, at the confidence setting we recommend for release gating.
Same test, same scoring, next to the other scanners:
- Real bugs found
- 54others 17 to 43
- False alarms
- 9others 15 to 72
- Findings that were real
- 86%others 37% to 53%
More real bugs and fewer false alarms than any of them, in 41.7s.
340
Real projects tested against
Public code it had never seen
231,847
Source files read
On every measured run
427
Checking modules
In the one engine
648
Tests on every change
Before any accuracy change ships
06 / The receipts
The flaw behind the breach is a named check here.
Recent breaches, and the named check that covers each disclosed flaw.
missing authentication
Tea
secrets in client code
Moltbook
broken authorization
Base44
object access, no owner check
Lovable
hallucinated dependency
Slopsquatting
Mapped from each incident's disclosed root cause to a shipped check. Not a claim that Vulkro would have prevented any breach.
07 / Enterprise and air-gap
Runs inside the perimeter. Leaves an evidence trail.
One binary on a laptop, in CI, or on a machine with no route to the internet at all, behaving the same in all three. Nothing to stand up, no repository permissions, no cloud account.
Deterministic and offline: same commit, same verdict, and nothing leaves the machine but a usage count. It also builds the evidence pack an auditor wants, control by control, with an SBOM and VEX, all local.