We are preparing a 2GP for security review and one of the common issues is CRUD/FLS. Our package notifies our server when opportunities or accounts change using triggers (webhook functionality). For example:

trigger MyOpportunityTrigger on Opportunity (after update, after delete) {
    if (Trigger.isUpdate) {
        for (Opportunity oppNew : Trigger.new) {
            Opportunity oppOld = Trigger.oldMap.get(oppNew.Id);

            // Check if any of the fields of interest have changed
            if (oppNew.Name != oppOld.Name || oppNew.StageName != oppOld.StageName || oppNew.Amount != oppOld.Amount ||
                oppNew.CloseDate != oppOld.CloseDate) {
                String content = MyWebhook.jsonContent(Trigger.new, Trigger.old);

    } else if (Trigger.isDelete) {
        // Handle the delete operation
        // Only the old version of the records is available
        String content = MyWebhook.jsonContent(null, Trigger.old);

The webhook class then passes this JSON content to an external URL versus HTTPS. It does not query or change any other objects, other than loading custom metadata types from the same package for various header values.

I am wondering if CRUD/FLS has to be considered here on the Opportunity object itself. My understanding from researching this so far is that the answer is "no", because the trigger would not be triggered by a user who does not have access to a given record. Is that correct?


1 Answer 1


The main question is should the webhook always be called, and receive the full data, regardless of the contextual user?

If yes to both points, CRUD/FLS is irrelevant and you should mark this as a false positive.

That this is in a trigger is not the key point. It is the purpose and requirements of the logic that helps you answer this question for yourself. Either way, always make sure to cover your false positives for your submission.

NB: I'm concerned that you're showing a callout from a trigger. This is not actually permitted (though there's a chance you're just generating the "command" for a callout, which will be done outside the current transaction, similar to the way I do this in this github repo example).

  • Thanks Phil for your answer. Your answers have been invaluable to us for developing our package! Commented Jan 10 at 15:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .