# Org hardening, data protection and guest users

Verified 2026-09 against <https://help.salesforce.com/s/articleView?id=sf.security_health_check.htm>
and <https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/>.

## Health Check

Health Check scores the org against Salesforce's baseline and lists each setting that differs. Treat
it as a release-cadence task, not a one-off:

- Password policy: length, complexity, expiry, reuse, lockout.
- Session settings: timeout, lock to IP, secure connections required, clickjack protection for
  Setup, non-Setup and Visualforce pages.
- Certificate and key management: expiry dates in particular — an expired certificate breaks
  integrations at the worst moment.
- Sharing settings: organisation-wide defaults that have drifted to more permissive than intended.

Record the items you deliberately diverge on, with the reason, so each review does not re-litigate
them.

## MFA, sessions and IP

- MFA is required for direct logins. Enforce it in the org rather than relying on users to enrol.
- Session timeout should reflect the profile: an integration user and a field sales user do not need
  the same policy.
- Login IP ranges on a profile are a strong control for integration and admin profiles, and a
  support burden for mobile users — apply them where they fit.
- "Lock sessions to the IP address they originated from" breaks some mobile and VPN scenarios; test
  before enabling broadly.

## Shield Platform Encryption

Encryption at rest, with real functional trade-offs. Decide **per field**, not per object:

| Consequence | What breaks |
|---|---|
| Filtering | `WHERE` on an encrypted field is restricted; some operators stop working |
| Sorting | `ORDER BY` on encrypted fields is not supported |
| Indexing and lookups | Unique and external-id behaviour changes |
| Reports and list views | Filters and groupings on encrypted fields may stop working |
| Formulas and rules | Encrypted fields cannot be used in some formula and criteria contexts |

Process that avoids surprises: list the candidate fields, find every report, list view, SOQL filter
and automation that touches each one, then encrypt in a sandbox and re-run them. Encrypt what the
regulation actually requires rather than everything that looks sensitive.

## Event Monitoring

The audit trail. Without it, questions like "who exported that report" have no answer.

Event types worth watching: logins and login-as, API calls, report exports, Apex executions,
Lightning page views, and permission set assignments. Pipe them somewhere with retention beyond the
platform's own window, and alert on the few that matter — bulk exports, login-as usage, and
permission changes on privileged profiles.

## Guest user hardening

The guest user is the unauthenticated internet. Work through this list for every public site:

- [ ] Guest profile has the minimum object permissions — ideally none.
- [ ] No guest sharing rule grants more than one specific, reviewed case.
- [ ] Guest user record access is read-only (the platform caps it there); anything else goes through
      Apex you control.
- [ ] "Secure guest user record access" org setting is enabled.
- [ ] Every `@AuraEnabled` method reachable from the site is listed, and each one: declares
      `with sharing`, enforces CRUD/FLS, validates every input, and does not trust an id parameter.
- [ ] Standard components on the site were checked for what they expose, not only custom ones.
- [ ] Files and attachments reachable by the guest user were reviewed.
- [ ] The site was tested in a logged-out browser — not only as an internal user.

Most published Salesforce data-exposure incidents come from this list, usually from a guest sharing
rule or an `@AuraEnabled` method that trusted its input.

## Integrations

- One integration user per integrating system, with a permission set granting exactly what it needs.
- Never a system administrator licence, and never a human's account.
- Named Credential with an External Credential for the secret. Custom settings and custom metadata
  are visible to anyone who can view setup, and they travel in change sets and unlocked packages.
- Where a Named Credential cannot carry the callout, the org's `Credential__c` object holds it.
  It is ordinary data, so it only works safely under three conditions: the secret sits in an
  **encrypted field**, **field-level security** is restricted to the integration user, and the
  records are **seeded per environment** rather than travelling in change sets or packages.
- Rotate credentials on a schedule, and confirm rotation does not require a code deploy.

## Code Analyzer v5 in CI

v4 (`sf scanner run`) was retired in August 2025. v5 runs PMD, ESLint, RetireJS, the Flow scanner,
CPD, regex rules and the Salesforce Graph Engine in one result set.

```bash
sf plugins install code-analyzer
sf code-analyzer run --workspace force-app --rule-selector Security --view detail
```

The Graph Engine is the part that matters for security: it performs path-based CRUD/FLS analysis
across call chains, which the per-file linters cannot. Configure engines, rule selectors and
severity thresholds in `code-analyzer.yml`, and agree which severities fail the build before turning
it on — otherwise the first run produces a backlog nobody triages.

## AppExchange listing

A listed package goes through a Salesforce security assessment. What it reliably looks for is the
same list as above: CRUD/FLS enforcement on every entry point, sharing declarations, no SOQL or DML
injection, no secrets in metadata, CSP-compliant resource loading, and no unreviewed third-party
JavaScript. Running Code Analyzer with the security rule selector and clearing the findings first
removes most of the back-and-forth.
