How Microsoft circumvented their own permissions (not really)

In this past week, I got out-hacked by Microsoft, a bug required us to change a value in an email table, and my AL-Fu failed me, but Microsoft came to the rescue. Check out the video:

https://youtu.be/O_MVKIO47_8


In this video, Erik walks through a real-world scenario from early August 2025 where a bug in Business Central’s email rate limiting feature left customers unable to send emails — and how Microsoft’s own fix cleverly circumvented their own permission system using an install codeunit.

The Problem: Email Concurrency Limit Set to Zero

Due to various setup configurations, some Business Central customers found themselves in a frustrating situation. The relatively new email rate limiting and concurrency functionality had a field — Email Concurrency Limit — that was set to zero. This effectively meant: “You can send zero emails at the same time.” Not ideal.

When attempting to fix it through the UI by opening the Set Email Rate Limit page, users were greeted with a validation message: “Concurrency limit must be between zero and 10.” The value was already zero, and the validation wouldn’t let you save it. Classic catch-22.

First Attempt: The RecordRef Trick

Erik’s first instinct was to write some AL code to directly modify the table. The problem? The Email Rate Limit table (table 8912) is marked with Access = Internal, meaning it’s part of the System App and only accessible by code within the System App itself.

No worries — there’s a well-known workaround using RecordRef to bypass the internal access restriction:

var
    Rec: RecordRef;
begin
    Rec.Open(8912);
    Rec.FindFirst();
    Rec.Field(5).Value := 10;
    Rec.Modify();
end;

Four lines of code. Problem solved… or so it seemed.

Second Problem: License Permissions

When running this code on a cloud sandbox, the FindFirst() call failed with the error: “Your license does not grant you the following permissions.”

This means that even as a Super user, the license itself does not include read permissions for this internal table. The RecordRef trick bypasses AL’s compile-time access checks, but it cannot bypass license-level permission restrictions. This is a fundamental limitation — no amount of clever AL code from an extension can get around it.

Microsoft’s Hack: The Install Codeunit

This is where things get interesting. Microsoft’s product group responded quickly with a fix, and Erik loved the elegance (and irony) of it: they used an install codeunit to circumvent their own permission system.

Why Install Codeunits Are Special

In AL, a codeunit can have different subtypes: Normal, Test, TestRunner, Install, and Upgrade. Install codeunits run when an extension is installed, and they have a critical property: they run outside the normal license and permission scope. There’s no user logged in per se — the code simply executes as part of the installation process.

This means an install codeunit can write to tables that no user — not even a Super user — has license permissions for.

The Implementation

codeunit 50100 "Install Hack"
{
    Subtype = Install;

    trigger OnInstallAppPerCompany()
    var
        Rec: RecordRef;
    begin
        Rec.Open(8912);
        if Rec.FindFirst() then begin
            Rec.Field(5).Value := 10;
            Rec.Modify();
        end;
    end;
}

The OnInstallAppPerCompany trigger runs for every company in the system during installation. The code uses the same RecordRef approach, but now it executes in the install context where license restrictions don’t apply.

Deployment Quirks

Erik ran into a subtle issue during testing. When deploying from VS Code directly, the install trigger didn’t seem to take effect immediately. The key insight is that the install codeunit runs as part of a single transaction across all companies. This makes sense — you can’t have an app installed successfully in one company but fail in another.

The fix that worked was:

  1. Uninstall the extension from Extension Management
  2. Republish the app
  3. Explicitly click Install from Extension Management

After doing this, the email concurrency limit was successfully set to 10, and email functionality was restored.

Cloud Deployment Process

Erik also walked through the cloud deployment pipeline, which goes through several stages:

  • Package validation — queued and then processed by an installation service
  • Package configuration storage — preparing the package for deployment
  • Deployment — usually the fastest step, comparable to deploying from VS Code

Key Takeaways

This scenario highlights several important concepts in Business Central development:

  • Internal access on tables prevents direct AL references from outside the owning app, but RecordRef can bypass the compile-time check
  • License permissions are a separate layer that even RecordRef cannot circumvent at runtime
  • Install and Upgrade codeunits run outside the normal license and permission scope, making them uniquely powerful for data fixes
  • The OnInstallAppPerCompany trigger executes within a single transaction spanning all companies

It’s a cumbersome approach — you have to build, deploy, and install an extension just to update a single field — but when the standard permission system blocks every other path, it’s a legitimate and effective hack. And there’s a certain delightful irony in Microsoft needing to use this technique to work around restrictions in their own platform.