Skip to content

A sensitivity marking dressed with harmless decoration still scores HIGH 100 ("Confidential - Draft", "Confidential FY25") #320

Description

@sectoramen

Follow-up to #307, which demoted a bare sensitivity marking out of HIGH. A marking carrying harmless decoration still saturates.

Reproduction

Same property name, values differing only in the decoration after the label. Measured on the #307 branch:

custom property value score band
Confidential 80 MEDIUM — correct after #307
Confidential - Draft 100 HIGH
Confidential FY25 100 HIGH
Confidential (Rev 3) 100 HIGH
Confidential - Project Nightjar acquisition 100 HIGH — correct, this one discloses

Why

classificationIsBareMarking (internal/validators/metadata/metadata_validator.go) splits the value on label punctuation and requires every part to be a known marking. -, (, ) and . are stripped as decoration, but the surviving tokens draft, fy25 and rev 3 are not in classificationMarkings, so the value reads as content and takes the full +0.5 CRITICAL weight.

That is the leaky part of the design, and it was known when #307 landed. The intent is "the value discloses content beyond its own handling class"; "extra tokens" is a proxy for that, and decoration defeats the proxy.

Why the obvious fix is wrong

Adding draft, final, rev, fy25, v2, copy, approved, … to classificationMarkings is the trap that produced #307 in the first place: an unbounded word list where the omissions are invisible, and where Confidential - Draft being MEDIUM while Confidential - Preliminary is HIGH is more confusing than either rule alone.

Directions worth considering

  1. Invert the test. Instead of asking "is every token a known marking?", ask "does the remainder look like an identifier?" — a codename, a person, a system, an account. Proper-noun capitalisation in the original (non-lower-cased) value, or a token that no dictionary/label list explains, is a better signal than membership in a marking list. It also degrades safely: unknown decoration stays MEDIUM rather than jumping to HIGH.
  2. Let the other validators decide. If a classification value contains something genuinely sensitive, PERSON_NAME / EMAIL / the project branch should find it on their own. The classification signal could then be a flat, modest contribution that never promotes. This was measured and rejected for METADATA: CUSTOM_PROPERTY scores HIGH 100 on the substring "confidential", so a Purview sensitivity label outranks a real secret #307 because it dropped Custom_Classification: SECRET - Project Nightjar to 70 against a pre-existing >= 90 assertion — but that assertion fails only because the project branch requires a literal project- with a hyphen. Fixing the project branch to recognise Project <Name> would make this direction viable, and is arguably the better fix overall.
  3. Strip a trailing revision/status suffix before the bareness test — a bounded, well-understood grammar (- Draft, FY\d\d, (Rev N), v\d) rather than an open-ended vocabulary. Narrower than (1), cheaper than (2).

My preference is (2) plus the project-branch fix, because it removes the proxy entirely rather than making it slightly less leaky.

Impact

Low. It over-scores a subset of labelled documents; it does not miss anything and nothing survives redaction because of it. The reason to fix it is the same as #307: HIGH is the band operators triage first, and labels crowding it push real findings down the list.

Acceptance criteria

  • Confidential - Draft, Confidential FY25, Confidential (Rev 3) score below HIGH
  • Confidential - Project Nightjar acquisition and Classification: SECRET - Project Nightjar stay at or above 90
  • the fix does not rest on an open-ended list of decoration words
  • real-corpus delta reported by band, since this changes scores on documents that are common in practice

Values shown are from synthetic fixtures.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions