Skip to content

GRANT with partial member list silently destroys existing access rules #89

@Chendodelangen

Description

@Chendodelangen

Bug Report: GRANT with partial member list silently destroys existing access rules

mxcli version: v0.3.0 (run ./mxcli --version to confirm; local build may show dirty suffix)
Mendix version: 10.24.15.93102
Severity: High — silent security regression, no warning or error


Summary

When issuing a GRANT statement on an entity that already has access rules for the specified roles, mxcli replaces the entire existing access rule with the new partial list instead of adding to it. The operation succeeds silently — no warning, no diff, no indication that existing permissions were destroyed.


Steps to Reproduce

The following is a self-contained reproduction. Role and entity names are illustrative; the behavior is not project-specific.

Step 1 — Create entity with existing access rules:

CREATE PERSISTENT ENTITY MyModule.Product (
  Name: String(200),
  Price: Decimal,
  IsActive: Boolean DEFAULT true
);

GRANT MyModule.Viewer ON MyModule.Product (
  READ (Name, Price)
);

At this point, DESCRIBE ENTITY MyModule.Product shows Viewer has READ on Name and Price.

Step 2 — Add a new attribute and grant access to it:

ALTER ENTITY MyModule.Product
  ADD ATTRIBUTE Notes: String(500);

GRANT MyModule.Viewer ON MyModule.Product (READ (Notes));

Expected result: Viewer gains READ on Notes in addition to the existing Name and Price.

Actual result: Viewer's entire access rule is replaced. Only Notes remains. Name and Price access is silently destroyed.

Verification:

DESCRIBE ENTITY MyModule.Product;
-- Shows: GRANT MyModule.Viewer ON MyModule.Product (READ (Notes))
-- Name and Price are gone

Real-World Reproduction (Original Discovery)

This was first observed on entity Masterdata.Characteristic. The before-state (from DESCRIBE ENTITY) was:

GRANT Masterdata.Employee, Masterdata.ITAdmin, Masterdata.ITEmployee, Masterdata.ProductionManager
  ON Masterdata.Characteristic (
    READ (CharacteristicType, CharacteristicName, StringValue, DateTimeValue,
          IntegerValue, DecimalValue, IsBooleanValue, Characteristic_Asset)
  );

After issuing:

GRANT Masterdata.Controller, Masterdata.FinanceOfficer
  ON Masterdata.Characteristic (READ (IsActive));

The roles Controller and FinanceOfficer — which previously had broader READ access — were reduced to only READ (IsActive). The security regression was not caught by mxcli lint and was only discovered during manual review in Studio Pro.


Why This Is Dangerous

  1. Silent failure — mxcli accepts the MDL and executes without error. Lint passes. DESCRIBE shows the new broken state with no indication anything was removed.
  2. Counterintuitive semantics — In SQL and virtually every other permission system, GRANT is additive. Developers naturally expect GRANT role ON t (READ (newField)) to add a privilege, not replace existing ones.
  3. Unreachable via Studio Pro — The GUI always preserves the full permission matrix. This broken state can only be produced through mxcli, making it invisible to developers who verify in Studio Pro after the fact.
  4. Silent production impact — Users with affected roles lose field-level access with no runtime error. The failure only surfaces when a user tries to read a field that was silently removed.

Expected Behavior

Option A (preferred): GRANT should be additive. GRANT role ON Entity (READ (newMember)) merges newMember into the existing access rule without touching other members.

Option B (acceptable): If replace-semantics are intentional or technically required by the Mendix model, mxcli should warn before destroying existing permissions:

Warning: GRANT for role MyModule.Viewer will remove existing READ access on:
  Name, Price
Use --replace to confirm, or include all members explicitly.

Workaround (until fixed)

The only safe way to add a member to existing entity access rules:

  1. Run DESCRIBE ENTITY Module.Entity — capture all current GRANTs
  2. For each affected role, reconstruct the complete GRANT including all existing members plus the new one
  3. Execute the full reconstructed GRANT

This is easy to forget, especially for AI-assisted or scripted workflows. A tool-level fix is strongly preferable.


Additional Context

This bug was discovered during AI-assisted Mendix development using Claude Code + mxcli. The agent issued syntactically correct targeted GRANTs based on reasonable assumptions about additive semantics, and the security regression was only caught during manual Studio Pro review.

We have also observed other operations where MDL is silently accepted but produces unexpected internal BSON state (list variable type serialization, association member linking). We will file those separately as they may warrant independent investigation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions