We’re running D365 Sales 9.2 and have a serious issue with our contract management module. Sensitive contract documents are being uploaded without proper classification labels, and our business rules aren’t catching them. We’ve configured classification requirements in the Business Rules engine, but documents still slip through uncategorized.
Here’s what we’re seeing in the audit logs:
Document ID: DOC-2847
Classification: NULL
Upload Status: SUCCESS
Business Rule: BR_CONTRACT_CLASS
Rule Status: BYPASSED
We need classification label enforcement at upload time, proper business rule customization to block unclassified documents, and a robust audit trail setup to track violations. This is creating potential data exposure risks as confidential client contracts are sitting in the system without proper access controls. Has anyone dealt with similar classification enforcement issues in the contract module?
Here’s a comprehensive solution addressing all three requirements:
Classification Label Enforcement:
First, fix your Business Rule execution. The rule needs to run on both Create and Update operations, with proper entity scope. However, as others noted, business rules won’t catch API bypasses. Implement a custom plugin on PreValidation stage:
public void Execute(IServiceProvider serviceProvider) {
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.MessageName == "Create" && context.InputParameters.Contains("Target")) {
var entity = (Entity)context.InputParameters["Target"];
if (!entity.Contains("new_classification") || entity["new_classification"] == null) {
throw new InvalidPluginExecutionException("Classification required");
}
}
}
Business Rule Customization:
Update your BR_CONTRACT_CLASS rule to include conditional branches for different contract types. High-value contracts (>$100K) should require “Confidential” or higher classification. Add a second rule that validates classification against contract type - NDA contracts must be marked “Restricted”, for example. Register both rules on the Contract and Document entities.
Audit Trail Setup:
Create a custom audit entity “Classification Violations” to track all attempts to upload unclassified documents. Your plugin should log to this entity before throwing the exception. Include fields for: User, Timestamp, Document Name, Contract ID, Attempted Classification (if any), and IP Address. Set up a Power Automate flow to alert your compliance team immediately when violations occur.
Additional recommendations:
- Enable D365’s built-in field-level auditing on the classification field
- Create a dashboard showing classification compliance rates by user and department
- Implement a grace period workflow that allows upload but flags for review within 24 hours, rather than hard blocking (configurable per contract type)
- For your legacy system integration, add classification validation in the middleware before calling D365 APIs
- Schedule weekly reports of contracts uploaded more than 48 hours ago that still lack proper classification
The combination of plugin enforcement, enhanced business rules, and comprehensive audit logging will close your data exposure gaps. The plugin is critical because it can’t be bypassed by users or API calls with elevated privileges.
The BR_CONTRACT_CLASS rule being marked as BYPASSED is telling. This usually means the rule scope is misconfigured. Go into Business Rules designer and verify the entity scope includes both the Contract entity AND the associated Document entity. Also check if your classification field is marked as business required - that alone won’t enforce it during programmatic uploads, but it’s a necessary foundation. What’s your current rule trigger set to? Create, Update, or both?
Another angle: even with proper business rules, you need a custom plugin for bulletproof enforcement. Business rules can be disabled by users with sufficient privileges. A plugin registered on the PreValidation stage of the Document Create message will catch everything, including API calls. The plugin should check for classification, reject if missing, and log the attempt to your audit table. This gives you the audit trail setup you need too.