Affected module
openmetadata-service — GlossaryTermRelationSettings (glossary term relation types)
Description
Glossary term relation types are stored in the glossaryTermRelationSettings Settings blob, and the system-seeded ones (relatedTo, synonym, partOf, hasPart, …) carry isSystemDefined: true. These are intended to be immutable — they cannot be edited or deleted.
That immutability is enforced on two of the three write paths, but not the third:
| Path |
Enforces immutability? |
| UI (Glossary Term Relations settings page) |
✅ edit/delete disabled for system-defined rows |
Dedicated API PUT /v1/system/settings/glossaryTermRelationSettings/relationTypes/{name} |
✅ throws "System-defined relation types cannot be updated." |
Generic API PUT /v1/system/settings (whole glossaryTermRelationSettings blob) |
❌ only blocks removing a system-defined type and duplicate names |
SystemResource.validateGlossaryTermRelationSettingsUpdate →
GlossaryTermRelationSettingsUtil.validateSystemDefinedRelationTypesPreserved(current, updated) currently checks only that system-defined names are still present. It does not compare fields, so an admin can change any field of a system-defined type (e.g. isTransitive, color, category, description, cardinality) through the generic settings PUT — silently bypassing the guard the UI and the dedicated endpoint enforce.
Steps to reproduce
GET /api/v1/system/settings/glossaryTermRelationSettings.
- In
config_value.relationTypes, take a system-defined entry (e.g. partOf) and flip a field — e.g. isTransitive: false → true — keeping isSystemDefined: true.
PUT /api/v1/system/settings with the modified blob.
Actual: 200 OK — the system-defined type is modified and persisted.
Expected: rejected, consistent with the UI and the dedicated relationTypes/{name} endpoint.
Proposed fix
Extend validateSystemDefinedRelationTypesPreserved to also reject field modifications to system-defined types (compare normalized current vs incoming, throw when a system-defined entry differs). This closes the gap on the generic settings PUT while leaving custom (non system-defined) types fully editable.
Notes
- Admin-only endpoint, so not a privilege-escalation issue — it's an integrity/consistency gap: system-seeded types should be immutable across all write paths.
- Related area: the same generic-PUT path historically also lacked duplicate-name validation (added later as
validateUniqueNames); this is the remaining unguarded invariant on that path.
Affected module
openmetadata-service—GlossaryTermRelationSettings(glossary term relation types)Description
Glossary term relation types are stored in the
glossaryTermRelationSettingsSettings blob, and the system-seeded ones (relatedTo,synonym,partOf,hasPart, …) carryisSystemDefined: true. These are intended to be immutable — they cannot be edited or deleted.That immutability is enforced on two of the three write paths, but not the third:
PUT /v1/system/settings/glossaryTermRelationSettings/relationTypes/{name}PUT /v1/system/settings(wholeglossaryTermRelationSettingsblob)SystemResource.validateGlossaryTermRelationSettingsUpdate→GlossaryTermRelationSettingsUtil.validateSystemDefinedRelationTypesPreserved(current, updated)currently checks only that system-defined names are still present. It does not compare fields, so an admin can change any field of a system-defined type (e.g.isTransitive,color,category,description,cardinality) through the generic settings PUT — silently bypassing the guard the UI and the dedicated endpoint enforce.Steps to reproduce
GET /api/v1/system/settings/glossaryTermRelationSettings.config_value.relationTypes, take a system-defined entry (e.g.partOf) and flip a field — e.g.isTransitive: false→true— keepingisSystemDefined: true.PUT /api/v1/system/settingswith the modified blob.Actual:
200 OK— the system-defined type is modified and persisted.Expected: rejected, consistent with the UI and the dedicated
relationTypes/{name}endpoint.Proposed fix
Extend
validateSystemDefinedRelationTypesPreservedto also reject field modifications to system-defined types (compare normalized current vs incoming, throw when a system-defined entry differs). This closes the gap on the generic settings PUT while leaving custom (non system-defined) types fully editable.Notes
validateUniqueNames); this is the remaining unguarded invariant on that path.