Skip to content

sf-audit: 61 Checks, Attack Chains, and Compliance Mapping

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 across OWASP, SOC 2, ISO 27001, HIPAA, and GDPR.

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 TwoFactorInfo and UserTwoFactorCredential objects 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.debug calls.
  • 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(), or stripInaccessible() guard. These are the most common source of OWASP A01 violations in Salesforce code.
  • Apex REST Endpoints: identifies @RestResource classes exposed without with sharing or with global scope, reachable by any authenticated user.
  • Visualforce XSS: scans Visualforce pages for unescaped {!expr} or apex:outputText without escape="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 LoginHistory for 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:pass strings. 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.