CTA Awareness study materials
CTA Awareness study resources

Guest User Reads 38,000 Cases Through an Apex Controller

CTA Awareness · Put your knowledge to work in context.

All case studies

Guest User Reads 38,000 Cases Through an Apex Controller

A healthcare services company runs a Customer Community Plus site for 60,000 patient-account contacts and a separate internal area for 900 staff. During a penetration test, testers logged in as a guest retrieved 38,000 Case records including patient names through an Aura component backed by an Apex class declared without sharing. The class queries Case with no filter and returns fields that are not on the page layout. The guest user's profile clone grants Read on Case, and object permissions were copied from an internal profile during a migration. Internal staff rely on role hierarchy plus criteria-based sharing rules; community users rely on sharing sets tied to the Account contact relationship. A middleware integration user still holds a System Administrator profile and a static password because the vendor says it cannot do OAuth. SSO with an external identity provider is being introduced. Leadership wants the site reopened in two weeks.

1. Enumerate the access paths that allowed this exposure and state the remediation order, distinguishing containment from the durable fix.

Read the worked answer

Containment first, within hours, not days. Disable the Aura component and its guest-visible page, revoke Apex class access from the guest user profile, and take the affected pages offline. Confirm whether the guest user can still retrieve Case through any other channel - REST, another Aura component, a Visualforce page, a flow screen - by auditing every component exposed to the site's public access settings. Check the org preference that restricts guest user record access and confirm the guest profile holds no administrative permissions.

Then the root cause. A class declared without sharing runs in system mode with respect to record sharing, so the guest's sharing model is irrelevant to that query; Apex also does not enforce field-level security unless you ask it to. The combination of a broad profile clone granting Read on Case, a guest-exposed controller and an unfiltered query is the actual defect - the sharing declaration alone is not. The durable fix is layered: declare classes with sharing by default, add WITH SECURITY_ENFORCED or strip inaccessible fields, and filter by the running user's account context rather than returning everything.

Then the governance fix, which is the part that prevents a repeat: a guest-accessible-code review gate, least-privilege permission set groups instead of profile clones, and a regression test that asserts a guest session receives zero rows.

Do not reopen on two weeks of pressure until the containment audit is complete.

2. How would you restructure the sharing model for 60,000 external users and 900 internal users so that this class of error is harder to make?

Read the worked answer

Separate the two audiences explicitly and lean on the platform's external sharing primitives. Set the internal organisation-wide default on Case to Private, keep the role hierarchy for staff visibility, and use a small number of criteria-based rules only where the hierarchy genuinely fails. For community users, resist the temptation to open internal defaults; instead keep the external default at Private and use sharing sets so an external user's visibility is derived from their contact's Account relationship, plus a narrow set of Account-based sharing rules for edge cases.

Structural choices that reduce risk: assign access through permission set groups with muting so a user cannot accumulate permissions from a copied profile; forbid profile clones as a provisioning mechanism; and make shared Apex run with sharing unless a documented, reviewed exception exists. Treat guest access as a separate, minimal identity with its own public access settings and no Apex controllers except those explicitly reviewed.

Add detection: a scheduled job or test that enumerates guest-visible components and asserts expected row counts, and periodic review of the guest user's effective permissions. Also verify the org-wide guest record access setting is not silently allowing shares to leak records.

Finally, document the external-vs-internal default in the architecture decision record, because the next developer who copies a controller from the internal site is the real risk you are managing.

3. Address the integration user and the SSO rollout. What would you change, and what risk remains?

Read the worked answer

Replace the static-password System Administrator integration user. Give it a dedicated integration profile or permission set group scoped to the objects and fields the middleware actually touches - no System Administrator, no View All Data, no Modify All Data. Then move authentication to OAuth 2.0 JWT bearer flow with a connected app and a digital certificate, so no human-held secret exists; certificates rotate on a schedule you control, and access is bound to pre-authorised users only.

Supporting controls: restrict the connected app by IP range, apply a session policy that cannot be satisfied interactively, monitor via login forensics and event monitoring, and confirm the integration user is excluded from SSO enforcement policies if the IdP flow would break machine login - but that exclusion must be an approved, documented exception with a compensating control, not an oversight.

On the SSO rollout: use My Domain, configure the identity provider with just-in-time provisioning and a matching federation identifier, enable MFA at the IdP, and pilot with a small internal cohort before enforcing. The risk that remains is dual identity paths: humans authenticating through the IdP while integrations still use a legacy mechanism creates an account nobody monitors. Track every non-SSO login and shrink that list deliberately.

The vendor's 'cannot do OAuth' claim should be tested with a proof of concept before it is accepted into the design - it is frequently a configuration gap rather than a product limit.