Use SecretText for sensitive text

Properties
LC0043 Warning Design Code Fix Ignore Obsolete

When calling external APIs, a common pattern is to pass an authorization token or API key as a plain Text value to HttpHeaders.Add('Authorization', ...). The platform stores that value in a form the AL debugger can read — during a regular or snapshot debugging session, anyone with debugging access can open the Variables window and read the credential in plain text.

The SecretText data type is designed to protect sensitive values from being exposed through the AL debugger when doing regular or snapshot debugging.

Protecting sensitive values with the SecretText data type on Microsoft Learn

Pass credentials as SecretText instead. The HttpHeaders, HttpClient, IsolatedStorage, and Rest Client types all provide overloads that accept SecretText parameters.

Example

procedure CallExternalApi(ApiKey: Text)
var
    Headers: HttpHeaders;
begin
    Headers.Add('Authorization', ApiKey); // Use SecretText for sensitive text [LC0043]
end;

Change the credential parameter to SecretText:

procedure CallExternalApi(ApiKey: SecretText)
var
    Headers: HttpHeaders;
begin
    Headers.Add('Authorization', ApiKey);
end;

IsolatedStorage

When storing or retrieving secrets, use the SecretText overloads:

procedure StoreSecret(Key: Text; Value: Text)
begin
    IsolatedStorage.Set(Key, Value); // Use SecretText for sensitive text [LC0043]
end;
procedure StoreSecret(Key: Text; Value: SecretText)
begin
    IsolatedStorage.Set(Key, Value);
end;

Rest Client

The System Application’s "Rest Client" codeunit provides SetAuthorizationHeader, which already accepts only SecretText. The rule catches the alternative pattern — calling SetDefaultRequestHeader with 'Authorization' as the header name and a plain Text value:

procedure SetCredentials(Credentials: Text)
var
    RestClient: Codeunit "Rest Client";
    AuthorizationTok: Label 'Authorization', Locked = true;
begin
    RestClient.SetDefaultRequestHeader(AuthorizationTok, Credentials); // Use SecretText for sensitive text [LC0043]
end;
procedure SetCredentials(Credentials: SecretText)
var
    RestClient: Codeunit "Rest Client";
    AuthorizationTok: Label 'Authorization', Locked = true;
begin
    RestClient.SetDefaultRequestHeader(AuthorizationTok, Credentials);
end;

When the diagnostic is reported

The rule flags a Text value passed where a SecretText overload exists:

  • HttpHeaders / HttpClientAdd(), TryAddWithoutValidation(), and GetValues() when the header name is Authorization. For GetValues, the fix is to call GetSecretValues with an array of SecretText instead.
  • IsolatedStorageGet() (the var parameter), Set(), and SetEncrypted() (the value parameter). These overloads require runtime 13.0 (Business Central 2024 release wave 1) or later.
  • Rest ClientSetDefaultRequestHeader() on the System Application’s "Rest Client" codeunit when the header name is Authorization.

The rule resolves the header name at compile time. It recognizes 'Authorization' as a string literal and as a Label variable. When the header name is passed through an intermediate Text variable or a method call, the rule cannot determine its value and does not report a diagnostic.

Unsupported scenarios

The rule cannot trace values across procedure boundaries. When the header name or credential is passed through a wrapper procedure as a Text parameter, the rule has no way to determine the value at compile time:

procedure SetUnprotectedCredentials()
begin
    MySetAuthorizationHeader('Authorization', 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIs');
end;

procedure MySetAuthorizationHeader(Name: Text; UnprotectedCredentials: Text)
var
    RequestHeaders: HttpHeaders;
begin
    RequestHeaders.Add(Name, UnprotectedCredentials);
end;

Here Name is a Text parameter — not a string literal or Label — so the rule cannot resolve it to 'Authorization' and the call to RequestHeaders.Add goes unflagged.

See also