Cross-Package Privilege Escalation via @namespaceAccessible

This lab teaches how unsafe exposure of Apex classes and methods through @namespaceAccessible can let other packages invoke privileged business logic, creating cross-package escalation paths that are difficult to detect during normal tenant testing.

Executive Summary

@namespaceAccessible is designed for controlled interoperability between packages in the same namespace family. Misuse happens when high-impact operations are exposed without strict caller validation, authorization gates, and parameter constraints.

In managed package ecosystems, this can create trust-boundary failures: a secondary package, extension package, or compromised namespace component invokes privileged methods that subscriber users should never trigger directly.

Salesforce Attack Surface

  • Namespace-accessible Apex APIs: service facades, helper classes, and utility gateways callable across package boundaries
  • Cross-package orchestration paths: extension package hooks invoking privileged methods in core package
  • Privileged data handlers: methods performing user management, secret retrieval, or system-mode operations
  • Caller trust assumptions: missing verification of package origin, intended caller role, and execution context
  • Parameter abuse vectors: caller-controlled IDs, object names, or action flags reaching sensitive sinks

Business Impact

  • Cross-package privilege escalation: low-trust package components trigger admin-grade operations
  • Data overreach across tenants: unauthorized access to records, metadata, or protected business logic outcomes
  • Security review failure risk: AppExchange review flags unclear trust boundaries and unsafe exposed methods
  • Blast radius expansion: one weak package integration weakens the entire package suite trust model
  • Forensics complexity: abuse appears as valid internal package-to-package invocation

PoC Use Cases

Use isolated package test fixtures to validate exploitability of namespace-accessible methods.

// Vulnerable anti-pattern
public with sharing class PrivilegedAccountOps {
    @namespaceAccessible
    public static void reassignOwner(Id recordId, Id newOwnerId) {
        // Missing caller trust validation and authorization checks
        Account acc = [SELECT Id, OwnerId FROM Account WHERE Id = :recordId LIMIT 1];
        acc.OwnerId = newOwnerId;
        update acc;
    }
}
  • A sibling package invokes reassignOwner with attacker-selected record IDs.
  • Method executes privileged mutation without verifying business authorization.
  • User gains indirect control over records outside expected entitlement scope.

Testing Methodology

  • Enumerate exposed API surface: list all @namespaceAccessible methods and classify by sensitivity
  • Trace sink operations: identify DML, auth, secret, and system-mode actions reachable from exposed methods
  • Caller simulation: test invocation from separate package contexts and constrained user profiles
  • Abuse case design: vary target IDs and operation flags to test horizontal/vertical privilege abuse
  • Evidence collection: capture call chain, caller context, and unauthorized impact for report quality

Secure Engineering Patterns

  • Minimize exposure: mark only necessary APIs as namespace-accessible
  • Caller-aware authorization: enforce explicit permissions and business ownership checks before sensitive action
  • Action segmentation: separate read-only integration APIs from privileged mutation APIs
  • Parameter hardening: reject caller-controlled arbitrary object names, record IDs, and privilege flags
  • Review gates: treat every new @namespaceAccessible method as a security design decision
// Safer pattern
public with sharing class PrivilegedAccountOps {
    @namespaceAccessible
    public static void reassignOwner(Id recordId, Id newOwnerId) {
        if (!FeatureManagement.checkPermission('PKG_Reassign_Owner')) {
            throw new SecurityException('Not authorized');
        }

        Account acc = [SELECT Id, OwnerId FROM Account WHERE Id = :recordId LIMIT 1];
        if (!isCallerAuthorizedForRecord(acc.Id)) {
            throw new SecurityException('Record out of scope');
        }

        acc.OwnerId = newOwnerId;
        update acc;
    }
}

Verification Checklist

  • Inventory of all @namespaceAccessible methods is maintained and risk-classified
  • High-impact methods enforce explicit authZ and business-scope validation
  • Namespace-accessible methods do not directly expose system-mode privileged sinks
  • Cross-package abuse test cases are included in CI security regression suite
  • Security review evidence documents rationale for every exposed integration API

Lab Exercises

Run this sequence to understand and remediate cross-package abuse:

  • Exercise 1: Enumerate and classify all namespace-accessible methods in a package
  • Exercise 2: Build a simulated extension package caller to invoke exposed APIs
  • Exercise 3: Reproduce unauthorized record mutation via weak authorization checks
  • Exercise 4: Implement caller-aware authorization and scope controls
  • Exercise 5: Re-test and produce AppExchange-ready remediation evidence