Skip to main content

Apex

These checks cover every *.cls and *.trigger file, in both the SFDX (force-app/main/default/classes/) and MDAPI (src/classes/) layouts.

vulkro-sf scan ./force-app

Checks​

CheckWhat it finds
SOQL injection (apex-taint-soql-injection)Untrusted input concatenated into Database.query(...) or other dynamic SOQL. Bind variables (:name) and String.escapeSingleQuotes(...) clear it.
escapeSingleQuotes outside quotes (escape-single-quotes-call)An escaped value placed in an unquoted slot: a field or object name, ORDER BY / LIMIT, a numeric or date position, an IN (...) list or a SOSL clause. Quoted, LIKE '%...%' and SOSL '*...*' wraps are safe.
Mass delete without authorization (mass-delete-unfiltered-no-authz)delete [SELECT ...] with no WHERE / LIMIT in an @AuraEnabled, @RestResource or webservice class with no isDeletable(), Security.stripInaccessible or USER_MODE gate (CWE-285).
CRUD on writesinsert / update / delete / upsert with no isCreateable() / isUpdateable() / isDeletable(), no WITH SECURITY_ENFORCED on the prior read and no AccessLevel.USER_MODE.
FLS on readsSOQL returning restricted fields with no isAccessible(), WITH USER_MODE or Security.stripInaccessible(AccessType.READABLE, ...).
USER_MODE migrationAn advisory on WITH SECURITY_ENFORCED so you can plan the move to USER_MODE.
SharingA class declared without sharing (or with no keyword) that reads or writes user-owned objects.
IDOR (broken-object-level-auth/idor)A method that takes an Id and selects by it with no ownership filter such as OwnerId = :UserInfo.getUserId().
Mass assignment (mass-assignment-json-deserialize-sobject)JSON.deserialize / deserializeUntyped of caller JSON into a record with no field allowlist.
Crypto misuseCrypto.generateAesKey(128) (use 256), ECB mode, hardcoded IVs, MD5 / SHA-1 for passwords.
Secrets in codeAPI keys, OAuth client secrets, JWT signing keys and passwords as Apex string literals.
Cleartext calloutshttp:// URLs as Apex literals. Named Credential endpoints are on the Named Credentials page.
CSRFApex REST methods that change state with no Authorization-header gate.
Reflected XSS (controller side)A controller property read from ApexPages.currentPage().getParameters() with no escaping. The page side is on Visualforce.
User enumerationDistinguishable error messages on login or password-reset endpoints.

Confidence is High when the source flows into the sink in the same expression, Medium when the source is an instance field set elsewhere, and Low when it is a static field set at class load.

Example​

Non-compliant: SOQL injection, a sharing violation and missing FLS.

public without sharing class AccountSearchCtrl {
@AuraEnabled
public static List<Account> search(String name) {
String query =
'SELECT Id, Name FROM Account WHERE Name = \'' + name + '\'';
return Database.query(query);
}
}

Compliant:

public with sharing class AccountSearchCtrl {
@AuraEnabled
public static List<Account> search(String name) {
return [SELECT Id, Name FROM Account WHERE Name = :name WITH USER_MODE];
}
}

See also: LWC and Aura, Cross-method engine, Methodology