ComplyCore — Data Protection & Security
Find the data-protection and security problems in your code while you write it, mapped to the regulation that applies to you.
ComplyCore scans for personal data reaching places it should not — logs, third-party calls, unencrypted storage, API responses — and tells you which obligation each finding touches under NDPR/NDPA (Nigeria), GDPR (EU/UK) and PCI-DSS v4.0 — and, when you turn them on, POPIA (South Africa), the Kenya and Ghana Data Protection Acts and UK GDPR.
What it looks at
ComplyCore analyses how a value is used, not merely where its name appears. A password in an import, a type annotation, or a Swagger description is not a finding. The same value interpolated into a log line, sent to a third party, or written to a row without protection is.
| Domain |
Examples |
| Sensitive data |
PII, financial data, credentials, government IDs (BVN, NIN, SSN, passport), biometrics, special-category data |
| Encryption |
Hardcoded secrets, weak crypto (MD5/SHA-1/DES), plaintext transit, unsafe cache writes |
| Database |
SQL built by string interpolation, embedded credentials, unrestricted or destructive statements |
| API security |
Unauthenticated routes, JWT misuse, permissive CORS, personal data in responses, missing rate limits |
| Secrets |
AWS, Stripe, GitHub, Google, Firebase keys, private keys, signing secrets |
| Governance |
Consent gaps around special-category data, erasure and portability obligations |
| PCI-DSS |
Cardholder data and sensitive authentication data — storage, logging, transmission |
| Payments |
Paystack / Flutterwave / Stripe webhooks accepted without a signature check; amounts taken from the client |
| AI providers |
Personal data sent to OpenAI, Anthropic, Gemini and others; request input placed in the system prompt |
| Accounts & uploads |
Sign-in or reset responses that reveal whether an account exists; uploads with no type or size limit (flagged high when they hold identity documents) |
Findings are suppressed when the value is already protected: hashed with bcrypt or Argon2, encrypted, masked, bound as a query parameter, or excluded from serialisation.
Quick fixes
Put the cursor on a finding and press Ctrl+. (Cmd+. on macOS). Where the fix is mechanical, ComplyCore offers it:
| Finding |
Fix |
| Personal data in a log |
Redact it, or mask it to the last four characters |
| Hardcoded secret or credential |
Read it from an environment variable (adds import os / "os" in Python and Go; System.getenv on the JVM) |
| Plaintext HTTP |
Switch to HTTPS |
| MD5 / SHA-1 |
Switch to SHA-256 (passwords need bcrypt or Argon2id, and the fix says so) |
CORS origin: "*" |
Read allowed origins from CORS_ORIGINS |
| Error detail returned to the client |
Return a generic message |
| "User not found" on sign-in or reset |
Same response whether or not the account exists |
| Paystack / Flutterwave webhook without a signature check |
Insert the HMAC-SHA512 / verif-hash check |
| Upload with no limits (multer) |
5 MB limit and a JPEG/PNG/PDF allowlist |
Fixes that need judgement, such as rewriting a query to bind its parameters, are not automated.
Accepting a finding
If a finding is a deliberate decision, record it next to the code with a reason. Ignore on this line and Ignore in this file in the quick-fix menu write the comment for you:
// complycore-ignore-next-line SD-THIRD_PARTY-pii-email -- Resend is our email processor (DPA signed)
await resend.emails.send({ to: user.email, subject, html });
complycore-ignore after code covers that line, and complycore-ignore-file covers the whole file. Rule ids accept a trailing * (SD-LOG-*). The same comments are honoured by the ComplyCore CLI and GitHub Action.
CI and the command line
The same scanner runs outside the editor with no account:
npx complycore scan . # text report, exit 1 on high findings
npx complycore scan . --format sarif -o complycore.sarif
Languages
JavaScript, TypeScript, JSX, TSX, Python, Go, Java, Kotlin, PHP, Dart / Flutter
Each language has its own lexer, so comments, docstrings, annotations, struct tags, Kotlin and Dart string templates, PHP "$var" and "{$obj->prop}" interpolation, and raw strings are understood rather than pattern-matched. On the JVM the rules know Spring (Web, Data, Security), JAX-RS, Ktor and Javalin; JDBC, JPA/Hibernate and Room; RestTemplate, WebClient and OkHttp; SLF4J, Log4j and Android logging; Redis templates, Kafka and RabbitMQ; and the OpenAI, Anthropic, Gemini, Spring AI and LangChain4j SDKs. In PHP they know Laravel (routes, middleware, Eloquent $fillable/$casts, Http, Cache, Log), Symfony attributes and Doctrine, WordPress (REST routes, admin-ajax, $wpdb, transients) and plain PDO/mysqli. In Dart they know Flutter's SharedPreferences versus flutter_secure_storage, Hive, Isar, Drift and sqflite, http and dio, Firebase and the analytics SDKs, and dart_openai, anthropic_sdk_dart and google_generative_ai.
Whole-project scanning
On opening a workspace, ComplyCore scans the whole repository and reports a single figure in the status bar — ComplyCore: 53 risks in ajo-app-backend — taking the project name from package.json. Opening a file adds its detailed, line-level diagnostics.
Team dashboard
Sign in and findings sync to your organisation's dashboard at app.getcomplycore.com: projects register themselves on first scan, admins add developers to projects, and compliance reports are generated per project and per framework. Findings resolve automatically once a scan no longer reports them.
Set complycore.requireAuth to false to scan locally without an account. Nothing leaves your machine in that mode.
Commands
| Command |
|
| ComplyCore: Scan Whole Project |
Rescan every file in the workspace |
| ComplyCore: Rescan Active File |
Rescan the current file |
| ComplyCore: Project Risk Summary |
Severity and domain breakdown |
| ComplyCore: Show Framework Breakdown |
Findings grouped by NDPR / GDPR / PCI-DSS |
| ComplyCore: Show Data Flow Risks |
Where sensitive values travel |
| ComplyCore: Show Logs |
Output panel → ComplyCore |
| ComplyCore: Log In / Sign Up / Log Out |
Account |
| ComplyCore: Menu |
Everything above from one click on the status bar |
Settings
Settings → ComplyCore
| Setting |
Default |
|
complycore.enabled |
true |
Master switch |
complycore.frameworks |
all |
Which regulations to report against |
complycore.severity |
— |
Minimum severity shown |
complycore.confidenceThreshold |
— |
Hide findings below this confidence (0–1) |
complycore.scanProjectOnStartup |
true |
Scan the workspace on open |
complycore.syncMode |
save |
When findings are sent to the dashboard: on open and save (save), or also while typing (live) |
complycore.syncIdleSeconds |
30 |
In live mode, how long a file must be idle before its findings are sent |
complycore.scanSecrets |
true |
Hardcoded credentials |
complycore.scanDatabase |
true |
SQL and storage |
complycore.scanApiSecurity |
true |
Route and response checks |
complycore.scanGovernance |
true |
Consent and data-subject rights |
complycore.scanPci |
true |
PCI-DSS rules |
complycore.scanDataFlow |
true |
Value-flow analysis |
complycore.includeTestFiles |
false |
Scan test files |
complycore.excludePatterns |
— |
Globs to skip |
complycore.requireAuth |
true |
Require sign-in before scanning |
complycore.apiUrl |
https://api.getcomplycore.com |
API endpoint |
What leaves your machine
Your source code never does. Analysis runs entirely inside the editor. When you are signed in, ComplyCore sends only the description of each finding:
- the rule that fired, its title, severity and confidence
- the line and column
- the category of data involved (
pii, financial, government_id, …) and the sink it reached
- the framework references (NDPR, GDPR, PCI-DSS, and the regional citations for POPIA, Kenya, Ghana and UK GDPR, so a framework you enable later still has history)
- the file path relative to your project, and the project name from
package.json
No file contents, no code snippets, no matched text, no variable values. A finding says "a government ID reaches a log at src/kyc.service.ts:988" — never what that line contains. Paths are workspace-relative by design, so your machine's folder structure and account name stay local.
Findings are sent when a file is opened or saved, not on every keystroke (complycore.syncMode). Set complycore.requireAuth to false to scan with no account at all. In that mode nothing is transmitted and no network request is made.
Questions about data handling: support@getcomplycore.com
Scope
Analysis is per-file: a value is traced through assignments, calls and interpolations within a file, not across module boundaries. ComplyCore finds where sensitive data is handled unsafely; it does not prove that data is safe everywhere else.
It complements commit-time tooling rather than replacing it. To block commits containing secrets, add gitleaks or git-secrets.
Support
getcomplycore.com · support@getcomplycore.com