Skip to content

GRANT/CREATE ASSOCIATION on Document-hierarchy entity silently strips sibling entities' inherited access rules; DOWNLOAD FILE creates empty action #867

Description

@WouterHooglandTOF

mxcli bug report (draft — needs lead developer approval before submitting)

mxcli version

v0.16.0 (2026-07-12T11:44:17Z)

Mendix version

10.24.20.105674 (from mx check output: "Mendix 10.24.20.105674")

Severity

High. Silently strips previously-granted read/write access on unrelated,
pre-existing entities — a security regression with no error or warning at the
time it happens. Only surfaces later via mxcli docker check / mx check
(CE0004/CE0005/CE0066), by which point the damage is already committed to the
.mpr file. Confirmed on this project (backup-mode copy; no production impact
here, but would be severe on a live model).

Summary

Three distinct operations in this project (module MiniCompetitie) each
independently trigger a "reconcile access rules" step that destructively
strips inherited-attribute read/write grants from unrelated, pre-existing
entities
in the same module — entities never referenced by the triggering
statement. A fourth, unrelated defect: DOWNLOAD FILE produces an empty
action when used to freshly create a microflow.

Bug 1 — reconciliation strips sibling entities' inherited-attribute grants

Triggers (all three reproduced independently, each sufficient on its own)

  1. CREATE ASSOCIATION from a new entity to an existing one, anywhere in the module.
  2. CREATE ENTITY ... EXTENDS <entity-with-its-own-access-grants> (e.g. extending
    MiniCompetitie.Document, which itself has a GRANT statement).
  3. GRANT <roles> ON <entity> (read *) / (read *, write *) — a wildcard
    entity-access grant on ANY entity in the module.

Effect

Every other entity in the module that:

  • extends (transitively) an entity with its own inherited attributes
    (e.g. System.FileDocument via an intermediate Document class), and
  • has existing GRANT statements referencing those inherited attributes

...loses the inherited-attribute portion of those grants. Own/direct
attributes and associations are preserved; anything inherited (FileID,
Name, Contents, HasContents, Size, DeleteAfterDownload from
System.FileDocument, or UUID/DocumentType/BewerkStatus from the
project's own MiniCompetitie.Document) is silently dropped from the grant.
Entities with no own attributes/associations (e.g. CSVExportFile,
OFormulier) lose their grants entirely (down to zero rules).

Console output during the triggering operation includes a line like:

Reconciled 10 access rule(s) for new association

or

Reconciled 10 access rule(s) in module MiniCompetitie

This is logged as informational, not an error — nothing signals that
destructive changes just happened to unrelated entities.

Reproduction (minimal, isolated)

Starting from a clean project (mxcli docker check → 0 errors):

-- Trigger 3 in isolation (no new entity, no new association):
grant MiniCompetitie.ContractBeheerder, MiniCompetitie.Inkoper, MiniCompetitie.VastgoedRegisseur
  on MiniCompetitie.NotitieBijlage (read *);

(where NotitieBijlage is any pre-existing entity extending System.FileDocument)

Before:

grant MiniCompetitie.FunctioneelBeheerder, MiniCompetitie.ContractBeheerder, MiniCompetitie.Inkoper, MiniCompetitie.VastgoedRegisseur
  on MiniCompetitie.Bijlage (read (DateCreated, IsDeleted, UUID, DocumentType, FileID, Name, DeleteAfterDownload, Contents, HasContents, Size, Bijlage_MiniCompetitie));
grant MiniCompetitie.DocumentGenerator on MiniCompetitie.Bijlage (read (FileID, Name, DeleteAfterDownload, HasContents, Size));
grant MiniCompetitie.Inkoper on MiniCompetitie.Bijlage (read (...8 attrs...), write (Name, Contents)) where '[...]';
grant MiniCompetitie.VastgoedRegisseur on MiniCompetitie.Bijlage (read (...8 attrs...), write (Name, Contents)) where '[...]';

After (same describe entity MiniCompetitie.Bijlage):

grant MiniCompetitie.FunctioneelBeheerder, MiniCompetitie.ContractBeheerder, MiniCompetitie.Inkoper, MiniCompetitie.VastgoedRegisseur
  on MiniCompetitie.Bijlage (read (DateCreated, IsDeleted, Bijlage_MiniCompetitie));
grant MiniCompetitie.Inkoper on MiniCompetitie.Bijlage (read (Bijlage_MiniCompetitie)) where '[...]';
grant MiniCompetitie.VastgoedRegisseur on MiniCompetitie.Bijlage (read (Bijlage_MiniCompetitie)) where '[...]';

DocumentGenerator's grant is gone entirely, and every inherited attribute
(UUID, DocumentType, FileID, Name, DeleteAfterDownload, Contents,
HasContents, Size) and the write permissions are gone from the remaining
three. MiniCompetitie.CSVExportFile and MiniCompetitie.OFormulier (no own
attributes) end up with zero grant statements at all.

mxcli docker check afterward reports:

[error] [CE0004] "No access rights granted." at Access rule of entity 'MiniCompetitie.Bijlage'
[error] [CE0004] "No access rights granted." at Access rule of entity 'MiniCompetitie.CSVExportFile'
[error] [CE0004] "No access rights granted." at Access rule of entity 'MiniCompetitie.OFormulier'
[error] [CE0005] "Constraint is set even though no read, change or delete access is granted." at Access rule of entity 'MiniCompetitie.CSVExportFile'
[error] [CE0005] "Constraint is set even though no read, change or delete access is granted." at Access rule of entity 'MiniCompetitie.OFormulier'
[error] [CE0066] "Entity access is out of date. Please update security..." at Domain model of module 'MiniCompetitie'

Attempted workaround that made it worse

Re-running GRANT ... (read (FileID, Name, Contents, HasContents, Size, DeleteAfterDownload))
to restore the stripped attributes does not restore them — the command
reports success (Result: read (...) showing only the attributes that were
already present, silently dropping the new ones) but on a second attempt it
cleared the row entirely (Result: (no access), and describe afterward
showed no grant statement at all for that role/entity). Ran REFRESH CATALOG FULL first on a later attempt — no change in behavior. There appears to be
no mxcli-only recovery path
once an entity's grants have been stripped this
way; only Studio Pro's domain-model security editor (or restoring from a
backup taken before the triggering statement) recovers the original rule.

Suspected root cause

The reconciliation logic that runs on association-create / entity-create
(when extending an entity that itself has access grants) / wildcard
entity-access grant appears to recompute "all entities in the module with
grants referencing generalized/inherited attributes" and rewrite their rule
attribute-lists from a source that only knows about each entity's own
(non-inherited) attributes — dropping anything resolved through a
generalization chain, and dropping affected role-rows to zero when the entity
has no own attributes at all to fall back to.

Bug 2 — DOWNLOAD FILE produces an empty action on fresh microflow creation

Reproduction

create or modify microflow MiniCompetitie.ZZZTestDownload (
  $Document: MiniCompetitie.Document
)
folder 'Objects/NotitieBijlage'
begin
  download file $Document show in browser on error rollback;
  return;
end;
/

mxcli check --references passes. mxcli exec reports "Created microflow"
with no error. But describe microflow MiniCompetitie.ZZZTestDownload
afterward shows:

create or modify microflow MiniCompetitie.ZZZTestDownload (
  $Document: MiniCompetitie.Document
)
folder 'Objects/NotitieBijlage'
begin
  -- Empty action
  @position(520, 200)
  return;
end;
/

mxcli docker check reports [error] [CE0008] "No action defined." at Action activity 'Activity'.

Reproduced with both a brand-new entity (extends System.FileDocument
directly) and the project's own pre-existing MiniCompetitie.Document type as
the parameter — same empty-action result both times, so this is independent
of entity type. The project's own pre-existing ACT_Document_Download
microflow (originally authored in Studio Pro, not by mxcli) round-trips fine
through describe (shows the real download file $Document show in browser on error rollback; text) — so describe/read of an existing DOWNLOAD FILE action works; exec/write of a new one does not. Matches the
documented syntax in this project's own write-microflows.md skill exactly
(download file $GeneratedReport show in browser;).

Workaround used for both bugs on this project

  • Create the new entity, its association, and its entity-access rules
    directly in Studio Pro (unaffected by Bug 1 — Studio Pro's own security
    editor does the generalization-aware recompute correctly).
  • Create the microflow (with its Download file activity) in Studio Pro
    instead of via mxcli exec (unaffected by Bug 2).
  • Continue using mxcli normally for everything else (nanoflow/microflow
    logic without a DOWNLOAD FILE activity, GRANT EXECUTE ON NANOFLOW/MICROFLOW, page/snippet edits) — confirmed safe in this session.

Diagnostic bundle

Available: mxcli-diag-20260809-175104.tar.gz (in project/, generated via
./mxcli diag --bundle -p "MIC.mpr"). The reconciliation steps are logged as
informational (msg":"execute", no error field), so the log itself doesn't
flag them as failures — the regression is only visible by diffing describe entity output before/after, as shown above.

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