
Salesforce Pentest: Apex Predator
A deep technical guide from Reco on pentesting Salesforce Experience Cloud "Aura" sites, covering how to enumerate guest-user-accessible sObjects via HostConfigController and SelectableListDataProviderController, and how to discover and invoke custom server-side Apex controller methods exposed to guest/authenticated users. It introduces novel techniques for extracting Apex method parameters from compiled Lightning Web Component JS (via the lri/moduleDefs structures), using ComponentController.getComponent and siteforce:routerInitializer to enumerate every site route/page and its Apex-backed components beyond what standard tools like AuraInspector find, plus an appendix of undocumented native controllers including an Aura-exposed GraphQL execution endpoint (RecordUiController.executeGraphQL). It closes with defensive guidance on monitoring AuraRequest events via Salesforce Shield to detect abuse.
What it is
Reco's operational playbook for pentesting Salesforce Experience Cloud Aura sites. The summary lists the controllers and the general approach; below are the concrete procedural details that make the techniques reproducible — the LWC parameter-extraction algorithm, the request tweaks needed to enumerate every page, and the exact detection query.
How it works — the parts the summary omits
Aura request basics. Calls go to /aura or /s/sfsites/aura (POST or GET). Three params matter: message (the actions list), aura.context, and aura.token — for guest requests the token is the literal string "null". Only apps like siteforce:communityApp support guest actions.
Extracting LWC Apex parameters (no pa array). Legacy Lightning components declare params in a structured pa array; LWCs do not, so you trace them through compiled JS in context.moduleDefs:
- In the
lriobject, find keys valued"apexMethod"— the key is the method in dot-notation (HC_ContextNavController.getContextNavData→ descriptorapex://HC_ContextNavController/ACTION$getContextNavData). - In the
cocode string, find the method's import string@salesforce/apex/Class.methodin the imports array and note its positional index — that index maps to the corresponding factory-function argument (6th import → 6th argo). - Salesforce wraps args in a helper (
l); findc = l(o), then search forc.default(— the object literal passed to it is the parameter map (siteLabel,language,showProducts,productsPosition). - Unsure of a type? Pass a deliberately invalid value (e.g. a list of lists); the error names the expected type:
Value provided is invalid for action parameter 'siteLabel' of type 'String'.
Full page enumeration (beyond AuraInspector). Tools that only parse app.js/bootstrap.js/appcore.js return a small fraction of Apex methods. Instead:
- Call
ComponentController.getComponentwithmarkup://siteforce:routerInitializerto get every route. - Re-run route enumeration under three cookie contexts — no cookies,
renderCtxfrom the home page,renderCtxfrom the login page — because the route set varies by session context; some sites only reveal the full method list one way. - To pull a specific page's components, call
getComponentwithmarkup://siteforce:pageLoaderusing the route'sid,view_uuid, andthemeLayoutType. Critical: inaura.context, change"uad": trueto"false"or this fails. Read results from the response'scontext(componentDefs+moduleDefs), not the action'sreturnValue.
This works even on sites that force-redirect to login — the "hidden" pages are still reachable directly, and Reco reports finding vulns in them at major companies.
Appendix controller specifics:
RecordGvpController.getRecordtakes a dot-separatedrecordDescriptor(recordId.recordTypeId.layoutType...fields.mode...); relationship fields encode the dot as;2(CreatedBy;2Name). Result lands incontext, notactions.ScopedResultsDataProviderController.getLookupItemsdoes keyword search across an object (scope,term) — useful whengetItemstimes out or to hunt terms like "Salary"/"Token" without knowing the field;additionalFieldspulls fields beyond the default layout.
What to do (defense)
Review guest-user sharing rules and guest-user profile permissions first, then audit Apex classes using Without Sharing. Monitoring requires a Salesforce Shield subscription (data lives only in Shield-exclusive event log files). Alert on guest-user GraphQL use and bursts of getItems; do not alert on getComponent (too common). Query:
SELECT Id, LogDate, Interval, LogFile, LogFileLength
FROM EventLogFile
WHERE EventType in ('AuraRequest')Caveats
Reco frames this as authorized-testing-only: DoS is always out of scope (Salesforce-authorized only), no infra/RCE/desync attacks, and the appendix controllers are "documented publicly by researchers" rather than novel here.
Technologies named here
- Salesforce Experience Cloud
- Burp Suite
- Caido
- Salesforce Aura Framework
- OWASP Zap
- Salesforce LWR framework
- AuraInspector
- Legacy Lightning Components
- Lightning Web Components
- Salesforce Shield
- Salesforce Guest User profile
- Salesforce
- GraphQL
Techniques named here
- Aura message/action enumeration
- Custom Apex controller invocation
- Legacy Lightning Component Apex method extraction
- LWC Apex method extraction from compiled JS
- Full site enumeration via ComponentController.getComponent
- Session-context route enumeration
- Page component retrieval via id/view_uuid/themeLayoutType
- Direct record retrieval via RecordGvpController.getRecord
Related in Offensive Security