Skip to content

Catch a mistyped domain without a vocabulary file - #32

Merged
kurtseifried merged 2 commits into
mainfrom
feat/domain-consistency
Aug 11, 2026
Merged

Catch a mistyped domain without a vocabulary file#32
kurtseifried merged 2 commits into
mainfrom
feat/domain-consistency

Conversation

@kurtseifried

Copy link
Copy Markdown
Contributor

domain is free text, so a typo silently mints a second domain that looks like a real one. A per-object schema check cannot see it — each object is individually valid, and the two spellings only disagree with each other.

No vocabulary file is needed to catch it

Within a framework version, the control-identifier prefix and the domain name are a bijection: MDS-01 is in Model Security, and everything in Model Security is MDS-nn. Currently 18 prefixes to 18 domains in both AICM and its questionnaire, exactly.

So a mistyped domain breaks the bijection the moment it lands, and filing a control under the wrong domain breaks it the other way. Verified against both failure modes by planting them:

# transposed letters in one control's domain
aicm/1.1.0: MDS is 'Model Security' in 12 objects but 'Model Secuirty' in .../MDS-02.json

# an MDS control filed under another domain
aicm/1.1.0: MDS is 'Model Security' in 12 objects but 'Logging and Monitoring' in .../MDS-02.json
aicm/1.1.0: domain 'Logging and Monitoring' spans identifier prefixes ['LOG', 'MDS']

Each report names the single offending file and the majority spelling it disagrees with, rather than listing every file that got it right.

This gives the source data the internal consistency a normalized domain object would have been introduced to guarantee — at the cost of one CI step rather than a permanent new object type.

The other half is not closed, and is recorded rather than closed quietly

A framework release also has a title, a publisher, attribution terms, and controlled vocabularies (the valid domain set, the valid responsibility-ownership values), and there is no object to attach any of that to. Adding a fact at framework level currently means adding a property to every control in the framework, which is the wrong shape for a fact that is true once.

That is now an open question in SCHEMA-STIX-OBJECT-EXTENSIONS.md rather than a silent gap. Two things are noted there that bear on how it should be answered:

  • Neither framework nor domain is a type in SecID's vocabulary, so introducing them would be a deliberate divergence from the alignment the rest of the type set follows — permissible under conventions § 3, but a decision to take explicitly, and one that mints permanent identifiers.
  • The likely shape if adopted is additive: keep the flat provenance properties for identity and object self-containment (they are the SecID components, and they must stay on the instance for it to remain readable outside its bundle), add optional references alongside, and have CI require the two to agree.

Verification

  • No object changes; objects/ is untouched.
  • coverage.py --check, the schema self-test, and the doc-discipline checks pass.
  • No copyrighted standard text is reproduced.

Raised from review of the AICM conversion.

@kurtseifried

Copy link
Copy Markdown
Contributor Author

Follow-up commit: the same typo class, one level up.

speification instead of specification silently drops the specification text, and every per-object check reports no problem — the schemas leave additionalProperties unrestricted, so the object is individually valid and there is nothing to compare it against. Demonstrated by planting it:

$ python3 tools/validate.py .../MDS-01.json
1 object(s) checked, 0 skipped, 0 problem(s)      # the text is gone

$ # the new CI step
.../MDS-01.json: x-control has no property 'speification' in schemas/x-control.json

Restricting the schemas would be the wrong fix. STIX 2.1 permits custom properties, so additionalProperties: false would make the published contract stricter than STIX and reject a consumer's legitimate extension — the maximum compatibility principle failing in the other direction. What a consumer may add and what the catalog may publish are different questions, and only the second is ours to enforce.

So the schemas stay permissive and CI holds the committed objects to the properties their own schemas define. Passes across all 1836 objects (9 standard STIX objects skipped).

schemas/README.md had recorded this as "the trade-off is that typos pass. Worth tightening once the model stabilises" — it now records why tightening the contract isn't the answer, and where the mitigation lives instead.

`domain` is free text, so a typo silently mints a second domain that looks like
a real one. A per-object schema check cannot see it: each object is individually
valid, and the two spellings only disagree with each other.

No vocabulary file is needed to catch it. Within a framework version the
control-identifier prefix and the domain name are a bijection -- MDS-01 is in
Model Security and everything in Model Security is MDS-nn -- currently 18
prefixes to 18 domains in both AICM and its questionnaire, exactly. So a
mistyped domain breaks the bijection the moment it lands, and filing a control
under the wrong domain breaks it the other way. Verified against both failure
modes by planting them: a transposed 'Model Secuirty' and an MDS control moved
to Logging and Monitoring are each reported against the single offending file,
naming the majority spelling it disagrees with.

This gives the source data the internal consistency a normalized domain object
would have been introduced to guarantee, at the cost of one CI step rather than
a permanent new object type.

The other half of that objection is not closed and should not be closed
quietly, so it is recorded as an open question instead: a framework release also
has a title, a publisher, attribution terms, and controlled vocabularies, and
there is no object to attach any of that to -- adding a fact at framework level
currently means adding a property to every control in the framework, which is
the wrong shape for a fact that is true once. Noted there: neither `framework`
nor `domain` is a type in SecID's vocabulary, so introducing them would be a
deliberate divergence from the alignment the rest of the type set follows and
would mint permanent identifiers, which is a decision to take explicitly rather
than in passing. The likely shape if adopted is additive -- keep the flat
provenance properties for identity and self-containment, add optional references
alongside, and have CI require the two to agree.

Raised from review of the AICM conversion.
The same typo class as the domain check, one level up. `speification` instead of
`specification` silently drops the specification text, and every per-object check
reports no problem: the schemas leave additionalProperties unrestricted, so the
object is individually valid and there is nothing to compare it against.
Demonstrated by planting it -- tools/validate.py reports "0 problem(s)".

Restricting the schemas would be the wrong fix. STIX 2.1 permits custom
properties, so additionalProperties: false would make the published contract
stricter than STIX and reject a consumer's legitimate extension -- the maximum
compatibility principle failing in the other direction. What a consumer may add
and what the catalog may publish are different questions, and only the second is
ours to enforce. So the schemas stay permissive and CI holds the committed
objects to the properties their own schemas define.

Passes today across all 1836 objects with 9 standard STIX objects skipped, and
catches the planted typo naming the file and the property.

schemas/README.md documented the trade-off as "worth tightening once the model
stabilises"; it now records why tightening the contract is not the answer and
where the mitigation lives instead.
@kurtseifried
kurtseifried force-pushed the feat/domain-consistency branch from 82c0a85 to 3d06f7e Compare August 11, 2026 22:45
@kurtseifried
kurtseifried merged commit 5a2aff7 into main Aug 11, 2026
6 checks passed
@kurtseifried
kurtseifried deleted the feat/domain-consistency branch August 11, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant