Seed security knowledge corpus (16 articles + 30 AL samples)

Converts Jesper's existing AL security-review prompt into BCQuality seed
knowledge articles so the al-security-review leaf has a real corpus to
match against. Mirrors the performance seed phase.

Articles under microsoft/knowledge/security/ (16):
- Permission model: follow-least-privilege-in-permission-sets,
  use-indirect-permissions-for-elevated-access,
  use-inherent-permissions-to-grant-minimal-access
- Secrets: never-hardcode-secrets-in-al,
  use-isolated-storage-for-module-and-company-secrets,
  prefer-azure-key-vault-for-production-secrets,
  use-secrettext-for-credentials, use-secrettext-with-httpclient,
  compose-secrets-with-secretstrsubstno,
  use-nondebuggable-when-parsing-secrets
- External calls: require-https-for-external-calls,
  set-timeouts-for-external-calls, do-not-put-credentials-in-urls
- Error handling: avoid-sensitive-data-in-error-messages,
  do-not-swallow-security-errors-silently
- Extensibility: do-not-expose-sensitive-data-in-event-publishers

Paired AL samples under samples/security/<slug>/{bad,good}.al, object
IDs 50200-50231 (no overlap with performance 50100-50140).

Rubber-duck findings addressed:
- HttpClient secret-URI: SetSecretRequestUri is on HttpRequestMessage
  (not HttpClient). Rewrote use-secrettext-with-httpclient and its
  good sample to use HttpRequestMessage + HttpClient.Send.
- InherentPermissions only grants access to same-extension objects;
  the sample now defines its own table 50230 "Sec Sample Lookup" and
  grants 'r' on that, not on Database::Customer.
- Reworked compose-secrets-with-secretstrsubstno bad.al away from
  Format(SecretText) (unreliable) to a plain Text+StrSubstNo anti-
  pattern.
- Moved normative guidance out of Description in three articles
  (compose-secrets-..., prefer-azure-key-vault-..., use-inherent-...)
  so it sits in Best Practice / Anti Pattern per READ contract.
- Added a companion helper codeunit (50231) to the indirect-permissions
  good sample so it actually demonstrates the controlled write path.
- Rebuilt the event-publisher good/bad pair on the same ExportCustomer
  scenario so the contrast is the shape of the event signature, not a
  different event.

Also: broaden samples/README.md object-ID range note to 50100-50299.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Jesper Schulz-Wedde 2026-04-17 13:39:50 +02:00
parent 32c40bbf1d
commit 0980397d27
47 changed files with 899 additions and 1 deletions

View file

@ -0,0 +1,29 @@
---
bc-version: [26..28]
domain: security
keywords: [error, disclosure, logging, label]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Avoid sensitive data in error messages
> **Seed article.** Converted from an existing security-review prompt to bootstrap the BCQuality security corpus. Domain stewards should expand, restructure, and refine as needed.
## Description
Errors surfaced to end users are routinely forwarded to support systems, captured in bug reports, and exported to telemetry. Server names, database names, usernames, connection strings, file paths, and stack excerpts in an end-user error message leak infrastructure detail to untrusted consumers and help an attacker map the environment.
## Best Practice
Raise end-user errors using localized Labels that describe the condition without naming infrastructure. Emit the actual detail (exception text, endpoint, correlation id) through the application's internal logging channel, where audience and retention are controlled.
See sample: `samples/security/avoid-sensitive-data-in-error-messages/good.al`.
## Anti Pattern
Error('Failed to connect to Server=PROD-SQL01;Database=NAV;User=admin: %1', Ex.Message); — every support ticket now carries the server name, database name, and service account.
See sample: `samples/security/avoid-sensitive-data-in-error-messages/bad.al`.