We shipped sf-audit v1.0 in April with 23 checks. It's now at 61, with attack chain detection, posture history tracking, and compliance tags on every finding.
We shipped sf-audit v1.0 in April with 23 checks. It's now at 61. Along the way it gained attack chain detection, posture history tracking, and compliance tags on every finding.
Here's what landed.
38 new checks, grouped by what they protect
Closing the SBS baseline gaps
Eight checks target the Salesforce Baseline Security (SBS) standard controls that were missing from the original set. These are the controls enterprise auditors reach for first:
| Check | SBS control | What it flags |
|---|---|---|
| Standard Profiles | SBS-ACS-005 | Users still on Standard User or System Administrator profiles instead of cloned, least-privilege profiles |
| SSO Enforcement | SBS-AUTH-001/002 | Auth providers configured but not enforced as the only login path |
| MFA Enforcement | SBS-AUTH-004 | Portal and Experience Cloud users without MFA-enforced permission sets |
| API Client Permission | SBS-ACS-006 | Permission sets granting API Enabled without a corresponding integration justification |
| Integration Users | SBS-ACS-007/008/009 | Named integration users sharing a real employee's account, or without IP restrictions |
| Content Links | SBS-FILE-001/002/003 | Salesforce Files shared via public links or accessible by guest users |
| Field History Tracking | SBS-DATA-004 | Sensitive objects with no field history tracking enabled |
| Data Classification | SBS-DATA-001/002/003 | Fields handling PII or PHI with no data sensitivity or compliance categorisation |
MFA beyond the checkbox
Three checks go past "is MFA on?" to verify who has actually registered a factor, and whether that factor is worth anything:
- Internal User MFA: scans every active internal standard user and flags those with no MFA method registered in the org's user record.
- MFA Registration: queries the
TwoFactorInfoandUserTwoFactorCredentialobjects to identify users whose only factor is SMS OTP (phishable). - MFA Method Strength: distinguishes authenticator apps, hardware security keys, and Salesforce Authenticator from SMS-based and email-based factors, and flags the weak methods as MEDIUM.
Can your SOC see what's happening?
Four checks verify that your org produces the log data needed to detect and respond to incidents:
- Deployment Identity: flags Connected Apps used in CI/CD pipelines with no unique owner, or that share credentials across environments.
- Apex Logging: checks whether scheduled and batch Apex jobs write structured log events rather than ad-hoc
System.debugcalls. - Event Monitoring: verifies that the Event Monitoring add-on is active and that key event types (Login, API, Apex, Report, ContentDistribution) are being collected.
- SIEM Integration: correlates Named Credentials, Remote Sites, Connected Apps, and scheduled Apex against known SIEM egress patterns to identify whether logs are being forwarded out of Salesforce.
Code and application security
Four checks extend the static analysis already in the plugin:
- Apex CRUD/FLS: flags Apex classes that perform DML or SOQL without an
isCreateable(),isAccessible(), orstripInaccessible()guard. These are the most common source of OWASP A01 violations in Salesforce code. - Apex REST Endpoints: identifies
@RestResourceclasses exposed withoutwith sharingor withglobalscope, reachable by any authenticated user. - Visualforce XSS: scans Visualforce pages for unescaped
{!expr}orapex:outputTextwithoutescape="true", the classic Salesforce XSS vector. - Anonymous Apex Audit: flags orgs where anonymous Apex execution has been used in production within the past 30 days, a persistent indicator of ad-hoc privileged code execution.
Platform hygiene and supply chain
Five checks cover the slow-burn risks that rarely trigger alerts but accumulate exposure over time:
- Certificate Expiry: queries the certificate store and warns when any org certificate expires within 60 days (HIGH) or 30 days (CRITICAL).
- Installed Packages: inventories managed and unmanaged packages, flagging packages from untrusted namespaces, packages inactive for 12+ months, or packages with full-admin permission sets.
- Release Updates: lists pending Salesforce release updates that your org has deferred past their enforcement deadline.
- Legacy API Versions: flags Apex classes compiled against API versions below 50.0 (Winter '21) and SOAP remote site registrations still targeting legacy endpoints.
- Enhanced Domains: checks whether Enhanced Domains URL isolation is enabled, Salesforce's recommended defence against cross-org session attacks.
Evidence of active attacks
Four checks look for conditions consistent with attacks already in progress:
- Transaction Security Policies: verifies that at least one automated threat-detection policy is active (e.g. report exports over 2,000 rows, login from new IP, API calls from unknown app).
- Failed Login Detection: queries
LoginHistoryfor credential stuffing patterns: 10 or more consecutive failures for a single username, or failures from more than 20 distinct source IPs within 24 hours. - Debug Log Access: identifies active debug log traces for production users. Live traces dump Apex variable values, including any credential strings the code touches.
- Trusted IP Ranges: flags IP ranges defined on profiles that bypass MFA, particularly ranges broader than a /24.
Data exposure
Three checks target the vectors most commonly behind insider-threat and accidental leak scenarios:
- Experience Cloud Site: flags live sites with self-registration enabled, guest-accessible pages, or unauthenticated API access.
- Custom Labels Credential: scans custom label values for patterns matching API keys, Bearer tokens, and Base64-encoded
user:passstrings. Custom labels are globally readable by all Apex code regardless of field-level security. - Report Folder Access: identifies public report folders shared with All Internal Users on objects containing PII (Account, Contact, Lead, Case). A user with no object-level permissions can still export a report they can see.
Attack chain ingredients
Three lightweight checks exist specifically to feed the chain engine:
- Escalation Perms: detects the permission cluster that enables privilege escalation: Assign Permission Sets, Manage Users, Author Apex, Modify Metadata, Manage Profiles.
- CORS Allowlist: flags wildcard origins (
*) or overly broad origins in the CORS allowed-origins list, which enable cross-origin credential exfiltration. - Guest Executable Apex: identifies Apex classes reachable by guest users via Visualforce or Experience Cloud that run without sharing enforcement.
Compound findings surface as named attack chains
After all 61 checks run, the engine in src/chains/ evaluates your org's active findings against five named attack scenarios. If enough ingredients are present for a realistic multi-step attack, a separate CRITICAL or HIGH chain finding appears in the report alongside the individual findings.
The five chains:
Unauthenticated bulk exfiltration
Trigger: unauth-foothold + (code-exec OR data-read-bulk OR data-write)
An unauthenticated guest foothold (from guest object permissions or guest-accessible Experience Cloud pages) combines with guest-executable Apex or public external sharing to read business records in bulk without any login credential.
Standard user → org takeover
Trigger: low-trust-authenticated OR unauth-foothold + (priv-esc OR org-takeover)
A low-trust authenticated user, or even a guest, combines with an escalation permission (Assign Permission Sets, Author Apex, Manage Users) to reach full org administrator control.
Credential theft → external pivot
Trigger: credential-theft + external-egress
Exposed secrets (hardcoded credentials in Apex, credentials in custom labels, active debug traces, or a broad CORS origin) combine with an external callout path (Named Credential or Remote Site) to move stolen credentials to attacker infrastructure.
SOQL injection → mass read
Trigger: code-exec + injectable dynamic SOQL + bulk-readable data
Injectable dynamic SOQL in a class without bind variables combines with a permissive sharing model or broad field-level security to let an attacker extract large datasets through a single endpoint.
MFA bypass → privileged compromise
Trigger: MFA weakness + highly-privileged account present
Weak MFA enforcement, trusted-IP MFA bypass ranges, or unregistered MFA for internal users, combined with the presence of ModifyAllData or ViewAllData accounts. A credential-stuffing or phishing attack can compromise an org admin with no second-factor challenge.
Each chain finding includes the specific contributing findings and a tailored remediation narrative.
Every run archives to a local history store
sf audit security now silently archives a JSON copy of its result after each run:
~/.sf/audit-history/{orgId}/sf-audit-{orgId}-{timestamp}.json
No configuration needed. The archive accumulates across runs.
View the trend:
sf audit history --target-org myOrg
Audit History: My Org (00D000000000001)
────────────────────────────────────────────────────────────────────────────────
# Date Score Grade CRIT HIGH MED LOW Δ Score
────────────────────────────────────────────────────────────────────────────────
1 2026-03-23 15:10 64 D 1 5 8 3 —
2 2026-04-09 11:22 81 B 0 2 5 3 +17
3 2026-06-11 09:45 88 A 0 0 4 5 +7
────────────────────────────────────────────────────────────────────────────────
Trend: ▲ +24 over 3 audits Best: 88 (2026-06-11 09:45) Worst: 64 (2026-03-23 15:10)
The command also writes an HTML timeline to your current directory. Flags: --limit (most-recent N runs), --output (write directory), --reports-dir (custom archive location).
Before/after diffs for remediation sprints
Compare any two audit JSON files:
sf audit diff baseline.json current.json
─────────────────────────────
Diff Summary
─────────────────────────────
Score delta +17
Grade D → B
New 0
Resolved 1
─────────────────────────────
Writes HTML and JSON diff reports to the current directory. Useful for pre/post comparisons after a remediation sprint, or before/after a Salesforce release cuts.
Every check maps to OWASP, SOC 2, ISO, HIPAA, and GDPR
Every check now carries compliance tags across five frameworks:
| Framework | Coverage |
|---|---|
| OWASP Top 10 | A01 Broken Access Control, A02 Cryptographic Failures, A03 Injection, A05 Security Misconfiguration, A06 Vulnerable Components, A07 Auth Failures, A09 Logging & Monitoring |
| SOC 2 | CC6.1 through CC9.2 |
| ISO 27001 | A.8.2, A.9.2, A.9.4, A.10.1, A.12.1, A.12.4, A.12.6, A.13.2, A.14.1, A.14.2 |
| HIPAA | 164.312(a), 164.312(b), 164.312(d), 164.312(e), 164.514 |
| GDPR | Art.5, Art.30, Art.32 |
| Salesforce Baseline Security | SBS-ACS, SBS-AUTH, SBS-CODE, SBS-DATA, SBS-DEP, SBS-FILE, SBS-INT, SBS-MON, SBS-OAUTH, SBS-CPORTAL, SBS-SECCONF |
Tags are embedded in the report output so findings can be filtered and mapped to a control framework without post-processing. Useful when you need to pull the subset of findings that map to a specific SOC 2 control for an auditor.
Upgrade
sf plugins install @cclabsnz/sf-audit@latest
To see all 61 check IDs and categories:
sf audit list
The --scoring-config flag and existing custom scoring files from v1.0 continue to work without changes.