Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/System Application/App/Email/src/Email/Email.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,16 @@ codeunit 8901 Email
begin
end;

/// <summary>
/// Integration event that allows overriding the filtering of related source records before they are shown.
/// </summary>
/// <param name="EmailRelatedRecord">The related source records to filter. Subscribers can apply their own filtering, for example to ignore security filtering when determining read permission.</param>
/// <param name="IsHandled">Out parameter to set if the event was handled. If set to true, the default filtering is skipped.</param>
[IntegrationEvent(false, false)]
internal procedure OnBeforeFilterRemovedSourceRecords(var EmailRelatedRecord: Record "Email Related Record"; var IsHandled: Boolean)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Security} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

OnBeforeFilterRemovedSourceRecords declares 'var IsHandled: Boolean' and the caller does 'if IsHandled then exit', allowing any subscriber in the same app to skip the entire security-filtering loop.

The XML documentation makes the bypass intent explicit: "Subscribers can apply their own filtering, for example to ignore security filtering when determining read permission." This matches the article's anti-pattern exactly: a var Boolean guard parameter on an IntegrationEvent whose name signals a security decision, followed by an unconditional exit that drops the publisher's check. The recommended fix is to restructure so subscribers can only tighten the filter (e.g., an OnAfterFilterRemovedSourceRecords event fired after the default filtering, where subscribers can add additional SetRange calls or call Error to deny access), rather than providing a hook that bypasses the default security filter entirely.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

begin
end;

/// <summary>
/// Integration event to add additional relations based on added relation to emails.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -745,8 +745,14 @@ codeunit 8900 "Email Impl"
procedure FilterRemovedSourceRecords(var EmailRelatedRecord: Record "Email Related Record")
var
AllObj: Record AllObj;
Email: Codeunit Email;
SourceRecordRef: RecordRef;
IsHandled: Boolean;
begin
Email.OnBeforeFilterRemovedSourceRecords(EmailRelatedRecord, IsHandled);
if IsHandled then
exit;

repeat
if AllObj.Get(AllObj."Object Type"::Table, EmailRelatedRecord."Table Id") then begin
SourceRecordRef.Open(EmailRelatedRecord."Table Id");
Expand Down
Loading