Salesforce standard SObject PII map
Salesforce ships dozens of standard SObjects (Account, Contact, Lead,
Opportunity, Case, User, ...) with a known field shape. An Apex
controller that SELECTs Email, Phone, Birthdate from one of
these objects is processing PII whether or not the developer ever
spells out "PII" in the code.
Vulkro carries an authoritative SF-only PII map keyed on
(sobject, field) and consults it on every Apex SOQL or DML statement
that references a standard SObject. The output is an informational
finding per (sobject, field) pair that downstream compliance reports
(GDPR RoPA, HIPAA, SOC2 CC6.8, NIST 800-53 SC-13) can ingest as
evidence that the codebase IS touching regulated data.
Covered SObjects
Six standard SObjects are mapped:
Account(billing / shipping address fields, phone, fax, website, and the Person Account variant withPerson*fields)Contact(email, phone, mobile, mailing address, birthdate, name)Lead(mirrors Contact for the prospect-facing field shape)Opportunity(commercial-sensitive fields: amount, close date, forecast category)Case(supplied email / phone, contact channels, description, subject)User(email, username, federation identifier, phone, address, workforce information)
Tier scheme
Each field is tagged at one of three tiers:
- Tier 1 (regulated PII): direct identifier, government ID, payment data, or login credentials. Reportable under GDPR Art 9, HIPAA, PCI-DSS. Emitted at Medium severity, High confidence.
- Tier 2 (personal information): personal detail or contact channel. Reportable under GDPR Art 6, CCPA personal information. Emitted at Low severity, High confidence.
- Tier 3 (commercial-sensitive): not regulated PII but worth surfacing for SOC2 CC6.8 (confidentiality) purposes. Emitted at Low severity, Medium confidence.
Custom objects are not covered
Fields on MyObj__c (custom object) or MyField__c (custom field)
are not in the map: their semantics are project-specific. The generic
naming catalog in vulkro (the same one that powers the language-
agnostic PII detector) handles those via field-name matching.
List<Contact> cons = [SELECT Id, Email, Phone FROM Contact];
// Vulkro emits Contact.Email (Medium) and Contact.Phone (Medium).
List<MyObj__c> cs = [SELECT Id, Email__c FROM MyObj__c];
// No SF-PII-map finding (custom object); the generic naming catalog
// applies based on the field name.
Example output
$ vulkro scan force-app
...
[MEDIUM] Apex SOQL accesses `Contact.Email` (tier-1 (regulated PII)
per Salesforce field-level reference). Any code path that reads this
field is processing regulated personal data; ensure access is gated
by an FLS / `WITH SECURITY_ENFORCED` check and that downstream
serialisation (Apex REST, Visualforce, LWC `@wire` returns) does not
expose the value to users who would not be entitled to see it on the
record page.
[LOW] Apex DML `update` writes a `Contact` record. This standard
SObject carries regulated personal data (per Salesforce field-level
reference); the operation should run under user mode (`as user` /
`WITH SECURITY_ENFORCED` on the prior SELECT) and the source fields
should be allow-listed against attacker-controlled input to defend
against mass-assignment.
What is not covered yet
- Cross-namespace references (
acme__Account) resolve to the bare object name after the namespace prefix; if a managed package redefines the field shape Vulkro will mis-tag. - The Health Cloud / Industries / Education Cloud standard SObjects are not yet in the map; they ship with their own field-level reference docs that we plan to fold in.
- The PII map is informational: by design it does not change scan
exit codes (so a clean codebase that legitimately processes PII
still passes the gate). The findings DO contribute to the
compliance evaluation when you run
vulkro compliance . --profile gdpror--profile nist-800-53.