Skip to content

False Positives

IDRuleSeverityFileStatus
FP-01ApexCRUDViolationHighObjectTeamMemberTriggerHandler.clsSuppressed — Trigger context
FP-02ApexCRUDViolationHighObjectTeamMemberController.cls (TeamMemberSelector)Suppressed — Intentional design
FP-03ApexSOQLInjectionHighObjectTeamMemberTriggerHandler.clsFalse Positive — Safe source
FP-04ApexSOQLInjectionHighShareRecordQueueable.clsFalse Positive — Whitelist
FP-05ApexSOQLInjectionHighObjectTeamMemberController.clsFalse Positive — Safe source
FP-06DebugStatementsLowMultiple filesAccepted Risk
FP-07Sharing (without sharing)MediumSyncOwnerInvocable.clsSuppressed — Flow-invoked system action
FP-08Sharing (without sharing)MediumObjectTeamMemberTriggerHandler.clsSuppressed — Trigger context
FP-09Sharing (without sharing)MediumObjectTeamMemberController.cls (ElevatedDmlOperations)Suppressed — CRUD checked in caller
FP-10Sharing (without sharing)MediumObjectTeamMemberController.cls (TeamMemberSelector)Suppressed — See FP-02
FP-11FLS CreateHighPostInstallHandler.clsFalse Positive — Admin context
FP-12FLS CreateHighObjectTeamMemberTriggerHandler.clsFalse Positive — CRUD checked in controller
FP-13CRUD DeleteHighObjectTeamMemberTriggerHandler.clsFalse Positive — System share records
FP-14CRUD DeleteHighShareRecordQueueable.clsFalse Positive — Permission checked before enqueue
FP-15CRUD DeleteHighSharingRecalculationBatch.clsFalse Positive — Admin-triggered batch
FP-16FLS UpdateHighObjectTeamMemberController.clsFalse Positive — isUpdateable() check exists
FP-17FLS UpdateHighSyncOwnerInvocable.clsSuppressed — Flow-invoked system action
FP-18DML Inside LoopsMediumObjectTeamMemberTest.clsAccepted — Test code only
FP-19DML Inside LoopsMediumSyncOwnerInvocableTest.clsFalse Positive — No actual DML in loop
FP-20Queries Without WHERE/LIMITMediumTeamMemberWizardController.clsAccepted — Bounded config object
FP-21DML Inside LoopsMediumObjectTeamMemberTriggerHandler.clsFalse Positive — DML is outside loop

FP-01: ApexCRUDViolation in ObjectTeamMemberTriggerHandler

Section titled “FP-01: ApexCRUDViolation in ObjectTeamMemberTriggerHandler”
AttributeValue
FileObjectTeamMemberTriggerHandler.cls
LineClass level
RuleApexCRUDViolation
SeverityHigh
StatusSuppressed with @SuppressWarnings

Reason: This trigger handler runs in trigger context where CRUD permissions have already been validated by the calling controller (ObjectTeamMemberController). The handler performs system-level operations including auto-creating Owner records and managing share records, which require elevated access.

Mitigation: CRUD checks are enforced in ObjectTeamMemberController before any DML operation reaches the trigger.


FP-02: ApexCRUDViolation in TeamMemberSelector

Section titled “FP-02: ApexCRUDViolation in TeamMemberSelector”
AttributeValue
FileObjectTeamMemberController.cls
Line129-150 (inner class)
RuleApexCRUDViolation
SeverityHigh
StatusSuppressed with @SuppressWarnings

Reason: The TeamMemberSelector inner class intentionally uses “without sharing” to allow users to view team members on records they have access to. This mirrors standard Salesforce AccountTeamMember behavior.

Mitigation: Users can only access this via LWC components on records they can already view. The recordId parameter comes from the UI context of an accessible record.


FP-03: ApexSOQLInjection in ObjectTeamMemberTriggerHandler

Section titled “FP-03: ApexSOQLInjection in ObjectTeamMemberTriggerHandler”
AttributeValue
FileObjectTeamMemberTriggerHandler.cls
Lines135, 305
RuleApexSOQLInjection
SeverityHigh
StatusFalse Positive

Reason: The object name used in dynamic SOQL is derived from a Salesforce ID using the platform method Id.valueOf(actualRecordId).getSObjectType().getDescribe().getName(). This cannot be manipulated by users.

Code Pattern:

String objectName = Id.valueOf(actualRecordId)
.getSObjectType().getDescribe().getName();
String query = 'SELECT OwnerId FROM '
+ String.escapeSingleQuotes(objectName)
+ ' WHERE Id = :actualRecordId';

Mitigation: Object name comes from Salesforce ID (not user input). Bind variables used for user-controlled values. Additional escaping applied as defense-in-depth.


FP-04: ApexSOQLInjection in ShareRecordQueueable

Section titled “FP-04: ApexSOQLInjection in ShareRecordQueueable”
AttributeValue
FileShareRecordQueueable.cls
Lines138-141, 163-167
RuleApexSOQLInjection
SeverityHigh
StatusFalse Positive

Reason: Share object names come from a hardcoded whitelist of standard objects or follow a deterministic pattern for custom objects.

Whitelist:

Map<String, String> standardShareObjects = new Map<String, String>{
'Account' => 'AccountShare',
'Contact' => 'ContactShare',
'Case' => 'CaseShare',
'Lead' => 'LeadShare',
'Opportunity' => 'OpportunityShare',
'Campaign' => 'CampaignShare',
'Order' => 'OrderShare'
};

Mitigation: Object names validated against whitelist. Custom objects follow safe pattern (ObjectName__c -> ObjectName__Share). Bind variables used for all user-controlled values.


FP-05: ApexSOQLInjection in ObjectTeamMemberController

Section titled “FP-05: ApexSOQLInjection in ObjectTeamMemberController”
AttributeValue
FileObjectTeamMemberController.cls
Line89
RuleApexSOQLInjection
SeverityHigh
StatusFalse Positive

Reason: Same as FP-03. Object name derived from Salesforce ID using platform API.

Mitigation: Object name from Id.getSObjectType().getDescribe().getName(). Cannot be spoofed. Bind variable used for record ID.


AttributeValue
FilesObjectTeamMemberTriggerHandler.cls, ShareRecordQueueable.cls, ExpiredTeamMemberCleanupBatch.cls
RuleDebugStatements
SeverityLow
StatusAccepted Risk

Reason: Debug statements are retained for production troubleshooting. They log only at ERROR/WARN levels and contain no sensitive data.

Content logged: Exception messages, record counts, job status information.

Mitigation: Debug output can be filtered via Salesforce Debug Log settings. No PII or credentials logged.

FP-07: Sharing (without sharing) in SyncOwnerInvocable

Section titled “FP-07: Sharing (without sharing) in SyncOwnerInvocable”
AttributeValue
FileSyncOwnerInvocable.cls
RuleSharing (without sharing)
SeverityMedium
StatusSuppressed with @SuppressWarnings

Reason: Flow-invoked Invocable Action that synchronizes team member Owner records when parent record ownership changes. Requires system-level access to query and update team member records across sharing boundaries.

Mitigation: @SuppressWarnings('PMD.ApexCRUDViolation') present. Only callable from Flow (admin-configured). Updates are limited to ObjectTeamMember__c records owned by the system.


FP-08: Sharing (without sharing) in ObjectTeamMemberTriggerHandler

Section titled “FP-08: Sharing (without sharing) in ObjectTeamMemberTriggerHandler”
AttributeValue
FileObjectTeamMemberTriggerHandler.cls
RuleSharing (without sharing)
SeverityMedium
StatusSuppressed with @SuppressWarnings

Reason: Trigger handler that manages share records and auto-creates Owner records. Runs in trigger context where the calling controller has already validated CRUD permissions.

Mitigation: CRUD checks enforced in ObjectTeamMemberController before any DML reaches the trigger. Share record operations require elevated access by design.


FP-09: Sharing (without sharing) in ElevatedDmlOperations

Section titled “FP-09: Sharing (without sharing) in ElevatedDmlOperations”
AttributeValue
FileObjectTeamMemberController.cls (ElevatedDmlOperations inner class)
RuleSharing (without sharing)
SeverityMedium
StatusSuppressed with @SuppressWarnings

Reason: Inner class used for DML operations that require system-level access (e.g., inserting/updating/deleting ObjectTeamMember__c records). The calling methods check isCreateable(), isUpdateable(), and isDeletable() before invoking this class.

Mitigation: CRUD checks performed in the outer controller methods before delegation to this inner class.


FP-10: Sharing (without sharing) in TeamMemberSelector

Section titled “FP-10: Sharing (without sharing) in TeamMemberSelector”
AttributeValue
FileObjectTeamMemberController.cls (TeamMemberSelector inner class)
RuleSharing (without sharing)
SeverityMedium
StatusSuppressed — See FP-02

Reason: Duplicate of FP-02. The TeamMemberSelector runs without sharing to allow users to see all team members on records they can access, mirroring standard AccountTeamMember behavior.

Mitigation: See FP-02 for full explanation.


AttributeValue
FilePostInstallHandler.cls
RuleFLS Create
SeverityHigh
StatusFalse Positive

Reason: Post-install script runs in admin context during package installation. Creates PermissionSetAssignment records, which are setup objects that don’t support standard FLS checks.

Mitigation: Runs only during package install/upgrade by an admin. PermissionSetAssignment is a setup object — FLS enforcement is not applicable.


FP-12: FLS Create in ObjectTeamMemberTriggerHandler

Section titled “FP-12: FLS Create in ObjectTeamMemberTriggerHandler”
AttributeValue
FileObjectTeamMemberTriggerHandler.cls
RuleFLS Create
SeverityHigh
StatusFalse Positive

Reason: Auto-creates Owner record in trigger context when the first team member is added to a record. The CRUD check (isCreateable()) is performed in the calling controller before the insert that fires this trigger.

Mitigation: Cross-class security flow: ObjectTeamMemberController validates CRUD -> DML fires trigger -> handler creates Owner. Scanner cannot trace this cross-class validation.


FP-13: CRUD Delete in ObjectTeamMemberTriggerHandler

Section titled “FP-13: CRUD Delete in ObjectTeamMemberTriggerHandler”
AttributeValue
FileObjectTeamMemberTriggerHandler.cls
RuleCRUD Delete
SeverityHigh
StatusFalse Positive

Reason: Deletes share records (system-managed sharing objects like AccountShare, ContactShare) during team member deletion. These are system objects that require elevated access.

Mitigation: isDeletable() check performed in ObjectTeamMemberController before the delete DML that triggers this handler. Share records are system-managed and don’t support standard CRUD checks.


FP-14: CRUD Delete in ShareRecordQueueable

Section titled “FP-14: CRUD Delete in ShareRecordQueueable”
AttributeValue
FileShareRecordQueueable.cls
RuleCRUD Delete
SeverityHigh
StatusFalse Positive

Reason: Async job that deletes share records as part of team member lifecycle. Permission is validated in the controller before the queueable job is enqueued.

Mitigation: isDeletable() checked in ObjectTeamMemberController before enqueueing. The queueable processes requests that have already passed authorization.


FP-15: CRUD Delete in SharingRecalculationBatch

Section titled “FP-15: CRUD Delete in SharingRecalculationBatch”
AttributeValue
FileSharingRecalculationBatch.cls
RuleCRUD Delete
SeverityHigh
StatusFalse Positive

Reason: Admin-triggered batch job that recalculates share records when object configuration changes. Only triggered from TeamMemberWizardController which checks isUpdateable() on the config object.

Mitigation: isCurrentUserManager() authorization check in TeamMemberWizardController before batch is executed. Only admins with FTS_App_Access permission set can trigger this.


FP-16: FLS Update in ObjectTeamMemberController

Section titled “FP-16: FLS Update in ObjectTeamMemberController”
AttributeValue
FileObjectTeamMemberController.cls
RuleFLS Update
SeverityHigh
StatusFalse Positive

Reason: The isUpdateable() check exists in the controller method before the update DML. Scanner failed to recognize the cross-method validation flow.

Mitigation: Schema.sObjectType.ObjectTeamMember__c.isUpdateable() is checked before any update operation. The check and the DML are in separate methods within the same class.


AttributeValue
FileSyncOwnerInvocable.cls
RuleFLS Update
SeverityHigh
StatusSuppressed with @SuppressWarnings

Reason: Flow-invoked Invocable Action that updates ObjectTeamMember__c Owner records when parent record ownership changes. Runs as a system action triggered by Flow.

Mitigation: @SuppressWarnings('PMD.ApexCRUDViolation') present. Only callable from admin-configured Flows. Updates are limited to the Owner role field on team member records.


FP-18: DML Inside Loops in ObjectTeamMemberTest

Section titled “FP-18: DML Inside Loops in ObjectTeamMemberTest”
AttributeValue
FileObjectTeamMemberTest.cls
RuleDML Inside Loops
SeverityMedium
StatusAccepted — Test code only

Reason: Test class creates test data in a loop (4 iterations). This is test-only code that never runs in production and is not subject to governor limit concerns at test scale.

Mitigation: Test code only. Loop is bounded (4 iterations). No production impact.


FP-19: DML Inside Loops in SyncOwnerInvocableTest

Section titled “FP-19: DML Inside Loops in SyncOwnerInvocableTest”
AttributeValue
FileSyncOwnerInvocableTest.cls
RuleDML Inside Loops
SeverityMedium
StatusFalse Positive

Reason: Scanner falsely flagged this test class. There is no actual DML inside a loop — the DML statements are sequential test data setup, not loop-enclosed.

Mitigation: No DML exists inside any loop in this test class. False detection by scanner.


FP-20: Queries Without WHERE/LIMIT in TeamMemberWizardController

Section titled “FP-20: Queries Without WHERE/LIMIT in TeamMemberWizardController”
AttributeValue
FileTeamMemberWizardController.cls
RuleQueries Without WHERE/LIMIT
SeverityMedium
StatusAccepted — Bounded config object

Reason: Queries Team_Sharing_Config__c without WHERE/LIMIT to retrieve all configuration records. This custom metadata-like object is inherently bounded — a Salesforce org will have at most ~30 records (one per configured object).

Mitigation: Team_Sharing_Config__c records are created only by admins through the wizard (one per object type). The practical maximum is ~30 records. Adding a LIMIT would break functionality.


FP-21: DML Inside Loops in ObjectTeamMemberTriggerHandler

Section titled “FP-21: DML Inside Loops in ObjectTeamMemberTriggerHandler”
AttributeValue
FileObjectTeamMemberTriggerHandler.cls
Lines222–239 (handleBeforeDelete method)
RuleDML Inside Loops
SeverityMedium
StatusFalse Positive

Reason: Scanner traces data flow from a for loop (L222–229) that collects IDs into sets, through to delete DML statements that execute after the loop ends (L234, L239). The loop contains no DML — it only calls Set.add(). All DML operations are bulkified and executed outside the loop.

Code Pattern:

// Loop only collects IDs — no DML here
for (ObjectTeamMember__c member : oldMembers) {
deletingMemberIds.add(member.Id);
if (member.Role__c != 'Owner') {
recordIdsToCheck.add(member.Record_Id__c);
}
}
// DML executes AFTER the loop, bulkified
List<SObject> sharesToDelete = getShareRecordsBulk(oldMembers);
if (!sharesToDelete.isEmpty()) {
delete sharesToDelete;
}
if (!recordIdsToCheck.isEmpty()) {
deleteOrphanedOwners(recordIdsToCheck, deletingMemberIds);
}

Mitigation: The code follows Salesforce bulk processing best practices — collect in loop, DML outside loop. Scanner incorrectly flags cross-boundary data flow as “DML inside loop”.


ControlStatusImplementation
CRUD checks in controllersImplementedisAccessible(), isCreateable(), isUpdateable(), isDeletable()
FLS enforcementImplementedPermission Sets control field access
SOQL injection preventionImplementedBind variables for user input, whitelist for object names
Sharing modelImplementedwith sharing on controllers, without sharing only where documented
Input validationImplementedNull checks, format validation, business rules
XSS preventionImplementedLWC framework handles output encoding
CheckResult
HTTP CalloutsNone — package makes no external calls
Named CredentialsNot used
External ObjectsNot used
Remote Site SettingsNot required