Salesforce Interview Prep

Module 5 — ANSWER SHEET (SEALED)

Companion to 05_Topic05_Security_Sharing.md — open ONLY after you have written your own attempt.

Protocol (file 00, M1→M5): write ≥2 hypotheses + 2 solution attempts before reading. Then compare your attempt against this sheet like an investigator compares a suspect's story to the evidence. The contrast IS the learning. Then REDO from memory, then do the drill.


INCIDENT 1 — THE SEARCH THAT RETURNED EVERYTHING

The problem restated

"Private" org, no-keyword class, LWC search returns 40 accounts the rep can't access. Why, and what's the complete fix?

Model answer (2-min interview version)

  • The context trap: Apex classes with no sharing keyword run in SYSTEM MODE — record access AND field access filters are off. OWD/Private is enforced by the UI and by Apex only when the class declares it. The dev conflated UI enforcement with Apex enforcement.
  • The three keywords: with sharing = enforce the running user's record access; without sharing = bypass (privileged jobs — justify + comment); inherited sharing (API 45+) = inherit the caller's mode — the recommended default (prevents accidental over- and under-sharing).
  • The complete fix (two layers): layer 1 = the keyword (inherited sharing); layer 2 = FLSwith sharing does NOT filter fields: Security.stripInaccessible(AccessType.READ, results).getRecords() (API 50+) or ... WITH USER_MODE (API 59+). Hygiene: return only what the UI renders, validate input, paginate.
  • One-liner: "Declare the context — never trust the org."

Self-grade — you "got it" if you named:

  • No keyword = system mode (the exact trap)
  • The three keywords + inherited as default
  • Two-layer fix: keyword (records) + stripInaccessible/USER_MODE (fields)
  • UI vs Apex enforcement conflation

THE REDO — model answer

public inherited sharing class AccountSearch {
    @AuraEnabled
    public static List<Account> find(String q) {
        return Security.stripInaccessible(AccessType.READ,
            [SELECT Id, Name FROM Account WHERE Name LIKE :q]).getRecords();
    }
}
// Layer 1: inherited sharing (record access) · Layer 2: stripInaccessible (FLS)

RETRIEVAL DRILL — model answers

  1. Default context? → System mode — no sharing, no FLS.
  2. Three keywords?with sharing (enforce user's record access), without sharing (bypass — privileged), inherited sharing (API 45+, inherit caller — recommended default).
  3. Why doesn't with sharing fully protect? → Record access only; fields are a separate FLS filter Apex bypasses by default.
  4. Security.stripInaccessible? → API 50+, strips denied fields (READ/UPDATE), returns StripInaccessibleResult (records + removed fields).
  5. USER_MODE vs SYSTEM_MODE?WITH USER_MODE enforces CRUD/FLS at query time (API 59+); WITH SYSTEM_MODE = explicit bypass (the default).

INCIDENT 2 — THE FIELD THE REP SHOULDN'T HAVE SEEN

The problem restated

Profile denies fields; the UI hides them; a custom component renders them anyway. Which filter is missing and what's the three-level enforcement?

Model answer (2-min interview version)

  • The false assumption: FLS is enforced by the UI layer (page layouts + field security) — NOT by Apex. A class selecting restricted fields returns them; a custom component renders whatever it received. with sharing is record-access only — fields are a separate filter.
  • The three-level enforcement hierarchy: (1) describe checkSchema.SObjectType.Candidate__c.fields.SSN__c.isAccessible() (granular, verbose); (2) Security.stripInaccessible(AccessType.READ, records).getRecords() (API 50+, bulk-safe, strips denied fields); (3) WITH USER_MODE (API 59+, enforcement inside the query, no post-processing).
  • Defense-in-depth (4 points): minimal projection (never SELECT sensitive fields "just in case"); FLS enforcement as the belt; UI renders only what was sent; dedicated sensitive endpoints with explicit permission gates (Custom Permission + FeatureManagement.checkPermission).
  • One-liner: "The UI hides; Apex must strip — and never SELECT what the UI shouldn't see."

Self-grade — you "got it" if you named:

  • UI enforces FLS, Apex doesn't
  • Three levels: describe / stripInaccessible (50+) / USER_MODE (59+)
  • StripInaccessibleResult (records + removed fields)
  • Minimal projection + dedicated sensitive endpoints

THE REDO — model answer

public with sharing class CandidateOverview {
    @AuraEnabled
    public static Candidate__c get(String id) {
        return Security.stripInaccessible(AccessType.READ,
            [SELECT Id, Name FROM Candidate__c WHERE Id = :id]).getRecords();
        // no sensitive fields in the SELECT; FLS enforced; DTO-style minimal projection
    }
}

RETRIEVAL DRILL — model answers

  1. Who enforces FLS in UI, who doesn't in Apex? → UI (layouts + field security); Apex returns whatever the query selects.
  2. Three mechanisms? → Describe isAccessible() (verbose); Security.stripInaccessible (API 50+, bulk); WITH USER_MODE (API 59+, query-time).
  3. StripInaccessibleResult gives?getRecords() (stripped) + getRemovedFields().
  4. USER_MODE vs SYSTEM_MODE? → USER_MODE enforces CRUD/FLS in-query; SYSTEM_MODE bypasses (default).
  5. Minimal-projection rule? → Never SELECT fields the UI shouldn't see; sensitive data via dedicated gated endpoints.

INCIDENT 3 — THE SEARCH BOX THAT RAN YOUR SOQL

The problem restated

Concatenated dynamic SOQL + payload → tautology. Reconstruct, defend, and answer the two follow-ups.

Model answer (2-min interview version)

  • The reconstructed query: ... WHERE Name LIKE '%%' OR Id != '' OR Name LIKE '%%' — a tautology: every row matches. User input became query syntax.
  • The three defense layers: (1) bind variablesWHERE Name LIKE :pattern (value bound, never parsed as syntax — kills the injection class); (2) String.escapeSingleQuotes() — for unavoidable dynamic strings (a patch, not a design); (3) whitelisting — dynamic object/field names can't be bound → validate against Schema describe or a hardcoded allowlist. User input is never a name.
  • Follow-up 1: escapeSingleQuotes is a patch on the concatenation pattern — it escapes a quote character, not the pattern; attackers target other surfaces (operators, numeric contexts). The fix is removing concatenation ("don't sanitize, restructure").
  • Follow-up 2: binding carries values only — field names, object names, ORDER BY columns need allowlists.

Self-grade — you "got it" if you named:

  • The tautology reconstruction
  • Bind variables as primary defense
  • escapeSingleQuotes as patch
  • Whitelisting for names (can't be bound)

THE REDO — model answer

String pattern = '%' + input + '%';
List<Account> recs = [SELECT Id, Name FROM Account WHERE Name LIKE :pattern];
// Dynamic names:
Set<String> allowed = new Set<String>{'Name','City','Zip'};
if (!allowed.contains(column)) { /* reject */ }
String q = 'SELECT Id, Name FROM Account ORDER BY ' + column;  // allowlisted only

RETRIEVAL DRILL — model answers

  1. Injected query?WHERE Name LIKE '%%' OR Id != '' OR Name LIKE '%%' — matches everything.
  2. Three defenses? → Bind variables; escapeSingleQuotes (legacy); whitelist/describe-validate names.
  3. Why isn't escaping complete? → Patch on concatenation; the pattern (user input in a query string) remains the hole — restructure with binding.
  4. What can't be bound? → Names (fields, objects, ORDER BY) — allowlists replace them.
  5. One-line rule? → User input is never query syntax and never a name.

INCIDENT 4 — THE NIGHTLY JOB THAT LEAKED PRIVATE DATA

The problem restated

Un-keyworded batch writes aggregates to a Public Read object; reps see other teams' revenue. Trace the chain and design the corrected job.

Model answer (2-min interview version)

  • The three-link chain: (1) no keyword → system mode reads all deals (intended for a summary job); (2) un-keyworded class = undocumented privilege (nobody decided); (3) the actual leak — the destination: Team_Summary__c OWD = Public Read → the summary inherits the destination's OWD, not the source's. Reviewers audit the read path and miss the write path.
  • The sharing chain (memorize): OWD (baseline) → role hierarchy (managers inherit, when enabled) → sharing rules (declarative group grants) → manual/Apex sharing (per-record __Share grants). Cumulative.
  • The corrected design: destination OWD Private + sharing rule (owner-based, "Team Managers" group); keyword policy — without sharing only with justification AND access-controlled output (else inherited sharing); defense-in-depth — correct ownership on rows + read-back test (rep-context query returns zero rows).
  • One-liner: "System-mode reads are fine; system-mode writes into public objects are the breach — the leak is the destination."

Self-grade — you "got it" if you named:

  • Three-link chain (keyword, aggregation, destination OWD)
  • "Leak is the destination"
  • The 4-link sharing chain
  • Private + sharing rule + read-back test

THE REDO — model answer

Team_Summary__c: OWD Private + sharing rule (owner-based → Team Managers group)
Batch: without sharing ONLY with justification (needs all deals) — output access-controlled
Read-back test: rep-context [SELECT ... FROM Team_Summary__c] returns 0 rows

RETRIEVAL DRILL — model answers

  1. Un-keyworded batch context? → System mode.
  2. Where was the leak? → The destination (Public Read object) — reviewers audit the read path, miss the write path.
  3. Sharing chain? → OWD → hierarchy → sharing rules → manual/Apex sharing.
  4. When is without sharing legitimate? → Job genuinely needs all data AND output is access-controlled — with a justification comment.
  5. Sharing rule vs manual share? → Rules: declarative, group-based, automatic. Manual: per-record user grants (__Share rows, Apex-managed).

INCIDENT 5 — THE HIERARCHY THAT OPENED EVERY DOOR

The problem restated

"Private" org; a director sees everything. Trace the access math and design genuine confidentiality.

Model answer (2-min interview version)

  • The access math (four sources): (1) OWD (baseline — Private here); (2) role hierarchy — everyone above the owner in the role tree inherits (roles are a tree, teams are a fiction); (3) sharing rules — the "Confidential" criteria rule granted ALL confidential deals to ALL "Directors+"; (4) manual/Apex sharing (none here). The picklist is data, not access: criteria rules only grant, never deny, and the hierarchy never reads the flag — the "confidential" marker made the data MORE visible.
  • Hierarchy mechanics: "Grant Access Using Hierarchies" checkbox per object; bypassed by without sharing, View All Data, system context.
  • Confidential design: hierarchy OFF for confidential objects (or a dedicated Private object with hierarchy off); rules scoped to named groups, never "roles and above"; access by explicit grants — structure, not flags.
  • One-liner: "Access is structure; flags are data."

Self-grade — you "got it" if you named:

  • Four access sources
  • Role tree vs team chart
  • Criteria rules grant, never deny; hierarchy ignores flags
  • Confidential = hierarchy off + named groups + explicit grants

THE REDO — model answer

Deal__c: Private + hierarchy DISABLED for confidential data
Sharing: grant to named "Confidential Reviewers" group (never "Directors+")
Confidential__c: display/process field only — never the access control

RETRIEVAL DRILL — model answers

  1. Four sources? → OWD, role hierarchy, sharing rules, manual/Apex sharing.
  2. Hierarchy control + bypasses? → "Grant Access Using Hierarchies" per object; bypassed by without sharing, View All Data, system context.
  3. Why does the criteria rule on the flag grant MORE? → Criteria rules add access; nothing reads the flag to deny; the hierarchy never reads it.
  4. Three-point confidential design? → Hierarchy off (or dedicated object), rules to named groups, explicit grants.
  5. "Roles are a tree, teams are a fiction"? → Role position (not team membership) decides hierarchy inheritance — mis-arranged roles include other teams "below."

INCIDENT 6 — THE PERMISSION SET THAT BECAME A CROWN

The problem restated

A sensitive custom permission in an "Everyone" group; 400 users hold it; audits fail. The four entities and the governance design.

Model answer (2-min interview version)

  • The four entities: profiles = baseline licenses + baseline access (lean by design); permission sets = granular additions without profile changes (the modern practice); permission set groups = role-based bundles; custom permissions = code-checked capability flags — FeatureManagement.checkPermission('Name').
  • The "Everyone" failure: bundling a sensitive capability into a broad group inverts the model — the capability became org-wide by assignment; custom permissions are invisible in most UIs, so nobody sees the crown until the audit. The Apex check only gates code paths — it can't stop a user who already has the flag. The blast radius is the assignment.
  • Governance design (4 points): (1) capability ≠ role — smallest justified group; (2) lean profiles + permission sets + groups; (3) audit: permission-set-assignment reports, group-membership reports, quarterly access reviews; (4) logging around sensitive checks — the trail shows who used the capability.
  • One-liner: "A permission is a key, not a badge — smallest set, smallest people, reviewed quarterly."

Self-grade — you "got it" if you named:

  • Four entities (one line each)
  • Assignment = blast radius; check gates code paths only
  • Lean profile + PS + groups practice
  • Reports + quarterly reviews + logging

THE REDO — model answer

Custom permission Manage_Compensation__c:
  removed from "Everyone" group → assigned to "HR Compensation" group (justified membership)
  checks: FeatureManagement.checkPermission(...) + logging on sensitive actions
Audit: permission-set-assignment report + group membership review — quarterly

RETRIEVAL DRILL — model answers

  1. Four entities? → Profiles (baseline), permission sets (additions), groups (bundles), custom permissions (code-checked flags).
  2. Why is the Everyone group a crown? → Broad assignment inverts the model; invisible in UIs until audit; the code check can't stop holders.
  3. What does FeatureManagement.checkPermission gate? → Code paths (sensitive actions) — not assignment; logging proves usage.
  4. Modern practice? → Lean profiles + permission sets + groups; smallest-group assignment.
  5. Two audit surfaces? → Permission-set-assignment reports + quarterly access reviews (group membership).

INCIDENT 7 — THE ENDPOINT THAT SERVED EVERYONE'S DATA

The problem restated

REST endpoint: full_access scope, without sharing, concatenated input, raw serialization. The five layers and the redesign.

Model answer (2-min interview version)

  • The five layers: (1) auth & scopes — Connected App scopes define the token's power; least privilege, never full_access; (2) CRUD/FLS + sharing — class context + enforcement (stripInaccessible/USER_MODE); (3) input validation — binding, String.isId, allowlists; (4) rate limiting — Connected App request limits (the 14,000-requests bot); (5) audit — Event Monitoring + login history.
  • The redesign: scope → api (no full_access); class → with sharing; permission gate → Schema.SObjectType.Account.isAccessible() + custom permission (FeatureManagement.checkPermission) + FLS; input → bind the Id + String.isId(); response → a DTO (5 fields) — never JSON.serialize(recs) of raw SObjects (it serializes every field and every FLS gap).
  • One-liner: "Trust the scope, not the story — and the response is the last filter: DTO it."

Self-grade — you "got it" if you named:

  • Five layers (scopes, CRUD/FLS+sharing, input, rate limit, audit)
  • full_access anti-pattern
  • Permission gate (CRUD + custom permission) + FLS
  • DTO response — never raw serialization

THE REDO — model answer

@RestResource(urlMapping='/partner/accounts/*')
global with sharing class PartnerAccountAPI {
    @HttpGet
    global static PartnerDTO get() {
        String id = RestContext.request.requestURI.substringAfterLast('/');
        if (!Schema.SObjectType.Account.isAccessible()) throw ...;
        if (!FeatureManagement.checkPermission('Partner_Read')) throw ...;
        List<Account> recs = Security.stripInaccessible(AccessType.READ,
            [SELECT Id, Name FROM Account WHERE Id = :id WITH USER_MODE]).getRecords();
        return new PartnerDTO(recs);   // 5 fields only
    }
}

RETRIEVAL DRILL — model answers

  1. Five layers? → Auth/scopes, CRUD/FLS+sharing, input validation, rate limiting, audit.
  2. Why is full_access the anti-pattern? → Org-wide API access for any token using the app — least-privilege scopes per integration.
  3. Permission gate — two checks in order? → Object CRUD (isAccessible) → capability (custom permission); plus FLS on the result.
  4. Why is raw serialization a leak? → It serializes every selected field (and FLS gaps) — a DTO with exactly the intended fields is the response filter.
  5. Input validation tools? → Bind variables + String.isId/pattern + field allowlists.

INCIDENT 8 — THE LEAK NOBODY COULD TRACE

The problem restated

Three compliance questions, zero answerable. The surface map and the audit-minimum.

Model answer (2-min interview version)

  • The surface map: Field History — who changed record fields (per-object policy); Field Audit Trail — the Setup-managed tracking policy; Setup Audit Trail (SetupAuditTrail) — who changed Setup (evidence only if read); Login History — who authenticated; Event Monitoring — who accessed data (API, exports, UI) — the ONLY surface that proves reads; Shield FLE — at-rest encryption (defense-in-depth, not audit).
  • The answer key: Q1 (who changed the record) → Field History (was disabled — "costs storage" was a policy decision that made the question unanswerable); Q2 (who changed the permission) → Setup Audit Trail (existed but unread); Q3 (who SAW the data) → Event Monitoring (structurally unanswerable without it — reads leave no trace anywhere else).
  • The audit-minimum (5 points): Field History on sensitive objects (tracked fields, budgeted); scheduled SetupAuditTrail review (monthly); Event Monitoring + anomaly alerting (bulk exports, off-hours); Shield FLE on crown jewels; retention + compliance mapping.
  • One-liner: "Field History proves changes; Event Monitoring alone proves reads."

Self-grade — you "got it" if you named:

  • Six surfaces (one line each)
  • Q1→Field History, Q2→SetupAuditTrail, Q3→Event Monitoring
  • Event Monitoring = only read-proof
  • Audit-minimum 5 points (incl. anomaly alerting + Shield)

THE REDO — model answer

Enable: Field History (sensitive objects, tracked fields)
Schedule: SetupAuditTrail SOQL review — monthly
License: Event Monitoring (API + exports + UI) + anomaly alerts (bulk/off-hours)
Encrypt: Shield FLE on SSN/salary
Retain: per compliance; alert on the alerters

RETRIEVAL DRILL — model answers

  1. Six surfaces? → Field History, Field Audit Trail, Setup Audit Trail, Login History, Event Monitoring, Shield FLE.
  2. Q1/Q2/Q3 mapping? → Q1 = Field History; Q2 = Setup Audit Trail; Q3 = Event Monitoring.
  3. Why only Event Monitoring proves reads? → Reads leave no trace in change logs or setup logs — only usage telemetry records them.
  4. Why isn't Shield audit? → At-rest encryption protects data; it records nothing about who saw what.
  5. Audit-minimum 5 points? → Field History policy, scheduled SetupAuditTrail review, Event Monitoring + anomaly alerts, Shield FLE, retention/compliance.

🏆 CAPSTONE — THE ORG WHERE ONE USER SAW EVERYTHING (model report)

  1. Clue-by-clue:
    • A → Incident 1: no keyword = system mode. Fix: inherited sharing + FLS (stripInaccessible/USER_MODE).
    • B → Incident 2: FLS enforced by UI, not Apex. Fix: minimal projection + FLS enforcement + component renders only what was sent.
    • C → Incident 7: full_access scope + without sharing + concatenation + raw serialization + no rate limit. Fix: least-privilege scope, with sharing, binding + String.isId, DTO, rate limits, Event Monitoring.
    • D → Incident 5: hierarchy enabled + over-broad criteria rule. Fix: hierarchy off for confidential + named-group rules + explicit grants.
    • E → Incident 6: sensitive custom permission in "Everyone" group. Fix: smallest-group assignment + quarterly reviews + assignment reports + logging.
    • F → Incident 4: batch wrote to Public Read destination. Fix: destination Private + sharing rule + keyword policy + read-back test.
    • G → Incident 8: no Field History, unread Setup Audit Trail, no Event Monitoring. Fix: Field History policy, scheduled review, Event Monitoring + alerts, Shield.
  2. Priorities: Tonight — stop the bleeding: revoke partner tokens + disable endpoint (C), restrict "Everyone" (E), deactivate leaky classes (A, B). This week — fix classes (keywords + FLS + DTO), destination OWD + rules (F), confidential-data hierarchy/rules (D), enable Field History + Event Monitoring (G). This quarter — the security program: five-layer endpoint standard, access-review cadence, audit-minimum, security regression in every release.
  3. The shared root cause: "The org assumed the platform filters by default: no keywords, no FLS enforcement, no scopes, no destination security, no access reviews, no audit — security was 'the platform's job,' so nobody declared anything." One disease: security by assumption, not by declaration.
  4. The 3 verification steps: (a) context regression — sandbox user cloned from a rep profile runs every new Apex entry point; results must match the profile's record/field access exactly; (b) endpoint penetration smoke — limited-scope token + injection payloads: denied fields absent, injection returns no rows, rate limit trips; (c) audit proof — rep-context query on the summary returns zero rows; Field History/Event Monitoring logs exist and are queryable.
  5. The 2-minute answer (say out loud): "The org's security failure is one disease: security by assumption. We assumed the platform filters by default — so classes ran system-mode, endpoints trusted scopes, destinations inherited public OWD, permissions were assigned to everyone, and nobody enabled audit. The fix is a program: every class declares its context, every endpoint passes the five-layer standard, every sensitive destination is access-controlled, access is reviewed quarterly, and Event Monitoring proves what happened — so the next question is answerable the same day, not in a breach investigation. Tonight I stop the bleeding — the endpoint, the Everyone group, and the two leaky classes — and from Monday, security is declared, never assumed."

KNOWLEDGE SPINE — rapid-fire (model answers)

  1. Default context of a no-keyword class? → System mode (no sharing, no FLS).
  2. Three sharing keywords? → with / without / inherited (API 45+).
  3. Recommended default keyword? → inherited sharing.
  4. Does with sharing enforce FLS? → No — record access only.
  5. FLS bulk one-liner? → Security.stripInaccessible(AccessType.READ, records) (API 50+).
  6. Query-time FLS one-liner? → WITH USER_MODE (API 59+).
  7. OWD values? → Private / Public Read Only / Public Read-Write / Controlled by Parent.
  8. Sharing chain? → OWD → hierarchy → rules → manual/Apex.
  9. Hierarchy bypasses? → without sharing, View All Data, system context.
  10. Criteria-based sharing rules can only? → Grant (never deny).
  11. SOQL injection defenses? → Bind variables, escapeSingleQuotes, whitelist names.
  12. Can you bind a field name? → No — allowlists.
  13. Lean access practice? → Lean profiles + permission sets + groups.
  14. Custom permission check in Apex? → FeatureManagement.checkPermission().
  15. Endpoint scopes? → Least privilege; never full_access.
  16. Never serialize what? → Raw SObjects — use a DTO.
  17. Proves record changes? → Field History.
  18. Proves Setup changes? → Setup Audit Trail.
  19. ONLY proof of reads? → Event Monitoring.
  20. At-rest protection? → Shield FLE (not audit).

INTERLEAVED PRACTICE SET — model answers

  1. Limit hunt: (a) Module 5 — system mode / no keyword (Incident 1); (b) Module 5 — FLS gap: with sharing doesn't filter fields (Incident 2); (c) Module 5 — SOQL injection (Incident 3); (d) Module 5 — destination leak: batch → Public Read object (Incident 4); (e) Module 5 — without sharing from a trigger: runs system-mode inside a user transaction — the keyword must be justified (Incident 1's contrast) — and Module 1's trigger-order context applies.
  2. Design (2 min): Endpoint (Connected App, api scope, least privilege); five layers: auth/scopes, CRUD/FLS + sharing (with sharing + stripInaccessible), input validation (String.isId + binding), rate limiting, audit (Event Monitoring); DTO with the 5 fields; prove access via Event Monitoring API events.
  3. Module-1 bridge: two parts — (1) the class keyword: without sharing with justification (job needs all data) or inherited sharing with privileged caller; (2) the destination: Private OWD + sharing rule + read-back test (Module 1's batch discipline × Incident 4's destination lesson). The keyword that silently under-reports: with sharing on a job that needs all data.
  4. Module-4 bridge: flows run in system context by default — a flow writing sensitive aggregates is the declarative twin of the un-keyworded batch; the fix is the same: Private destination + sharing rules + fault path + reconciliation (Module 4 Incident 6), plus the access-matrix discipline (Module 4 Incident 5) for screen flows touching sensitive fields.
  5. One-card answer (5 bullets + incident map): (1) Cause: system mode — no keyword or without sharing (I1); (2) Fix layer 1: with sharing/inherited sharing for record access (I1); (3) Fix layer 2: FLS via stripInaccessible/WITH USER_MODE (I2); (4) Hygiene: minimal projection, never expose fields the UI doesn't render (I2); (5) Verify: Debug-as-user / cloned-profile user regression (I1/I7).

THE ONE-CARD ANSWER KEY (carry this)

"A user can't see data returned by your Apex class — why?" — 5 lines:

  1. Cause: the class runs in system mode (no sharing keyword, or without sharing) — no record-level or field-level enforcement.
  2. Fix layer 1 (records): with sharing / inherited sharing — the keyword turns the running user's sharing back on.
  3. Fix layer 2 (fields): Security.stripInaccessible(AccessType.READ, records) (API 50+) or WITH USER_MODE (API 59+) — with sharing does NOT filter fields.
  4. Design: minimal projection — never SELECT what the UI shouldn't see; dedicated gated endpoints for sensitive fields.
  5. Verify: test with a cloned-profile user (the rep's exact context), assert the returned record/field set matches the profile exactly.

Numbers/names to say cold: system mode default · with/without/inherited (45+) · stripInaccessible (50+) · USER_MODE (59+) · OWD: Private/PRO/P RW/Controlled by Parent · chain: OWD→hierarchy→rules→manual · bind variables / escapeSingleQuotes / whitelist · FeatureManagement.checkPermission · five endpoint layers · DTO responses · Field History / SetupAuditTrail / Event Monitoring (only read-proof) / Shield FLE.

On this page

INCIDENT 1 — THE SEARCH THAT RETURNED EVERYTHINGThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 2 — THE FIELD THE REP SHOULDN'T HAVE SEENThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 3 — THE SEARCH BOX THAT RAN YOUR SOQLThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 4 — THE NIGHTLY JOB THAT LEAKED PRIVATE DATAThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 5 — THE HIERARCHY THAT OPENED EVERY DOORThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 6 — THE PERMISSION SET THAT BECAME A CROWNThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 7 — THE ENDPOINT THAT SERVED EVERYONE'S DATAThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answersINCIDENT 8 — THE LEAK NOBODY COULD TRACEThe problem restatedModel answer (2-min interview version)Self-grade — you "got it" if you named:THE REDO — model answerRETRIEVAL DRILL — model answers🏆 CAPSTONE — THE ORG WHERE ONE USER SAW EVERYTHING (model report)KNOWLEDGE SPINE — rapid-fire (model answers)INTERLEAVED PRACTICE SET — model answersTHE ONE-CARD ANSWER KEY (carry this)