chore(cats): classify nine verified false-positive families from run 20260730T220551Z - #640
Merged
Merged
Conversation
…20260730T220551Z
Adds rules 61-69. Each was verified against the run's actual request and
response bodies before being written, and the set was dry-run against a
throwaway copy of the database first: 128 matches, no rule touching a 5xx,
and no single rule over the 5% share-of-true-positives threshold (the
largest, FEEDBACK_TARGET_FIELD_CROSS_FIELD_400, is 31/670 = 4.6%).
True positives drop 670 -> 542.
XXE_NOTES_CONTENT_NOT_PARSED (20)
TMI has no XML parser. All 20 responses returned the payload
HTML-escaped ("]>&test;") with zero entity expansion.
MASS_ASSIGNMENT_DECLARED_WRITABLE_FIELD (10)
timmy_enabled is a declared, non-readOnly property of
TeamProjectNoteBase and AssetBase. CATS flags it on a name heuristic.
MASS_ASSIGNMENT_SSE_STREAM_ENVELOPE (3)
chat/sessions streams text/event-stream; CATS runs a field-echo
heuristic over the notAJson envelope, where no JSON object exists.
IDOR_EMPTY_RESULT_SET (9)
Every finding returned total 0 -- the filter matched nothing, so
nothing was disclosed. Scoped to total==0 so a leak still surfaces.
FEEDBACK_TARGET_FIELD_CROSS_FIELD_400 (31)
target_field is valid only with target_type=threat_classification, a
cross-field rule not expressible in OpenAPI.
WHITESPACE_FIELD_NAMES_IGNORED_2XX (29)
A whitespace-mangled field name is an unknown key the decoder ignores;
TMI declares no additionalProperties:false. Verified all 29 mangled
only OPTIONAL fields -- none bypassed a required field. The rule
carries a note to re-verify that if the request models change.
PREFERENCES_ALREADY_EXIST_409 (11)
/me/preferences is a per-user singleton: POST creates, PUT updates.
PREFERENCES_FREEFORM_JSON_ECHO (1)
UserPreferences declares free-form per-client objects; size, client
count and key pattern are still enforced in the handler.
THREAT_MODEL_RESTORE_NOT_DELETED_409 (14)
Restoring a non-deleted threat model is correctly a conflict. The
older "not in a deleted state" rule no longer matches the server's
current wording ("Threat model is not deleted").
Deliberately NOT suppressed:
The 428 "Not matching response schema" findings -- a CATS defect being
researched under #637. Suppressing them would hide genuine schema
regressions in the resources that matter most.
The /saml/providers/{idp}/users 401s (19) and /me/groups/{id}/members
403s (12). These are seeding and configuration gaps, not false positives;
a rule would mask real authorization bugs. Fix the fixtures instead.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnrVyySuyJFqcMxB8q3pNc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds false-positive rules 61-69 from the 2026-07-30 CATS campaign
(
20260730T220551Z, v1.6.2 @ 2de6d9c). True positives drop 670 -> 542.Every rule was verified against the run's actual request and response bodies before
being written, and the whole set was dry-run against a throwaway copy of the database
first — the committed rules file was untouched until it passed:
FEEDBACK_TARGET_FIELD_CROSS_FIELD_400, is 31/670 = 4.6%XXE_NOTES_CONTENT_NOT_PARSED]>&test;), zero entity expansionFEEDBACK_TARGET_FIELD_CROSS_FIELD_400target_fieldis valid only withtarget_type=threat_classification— a cross-field rule not expressible in OpenAPIWHITESPACE_FIELD_NAMES_IGNORED_2XXadditionalProperties:falsein the contractTHREAT_MODEL_RESTORE_NOT_DELETED_409PREFERENCES_ALREADY_EXIST_409/me/preferencesis a per-user singleton: POST creates, PUT updatesMASS_ASSIGNMENT_DECLARED_WRITABLE_FIELDtimmy_enabledis a declared, non-readOnly property; CATS flags it on a name heuristicIDOR_EMPTY_RESULT_SETtotal: 0— nothing disclosedMASS_ASSIGNMENT_SSE_STREAM_ENVELOPEnotAJsonenvelopePREFERENCES_FREEFORM_JSON_ECHOUserPreferencesdeclares free-form per-client objectsThe one rule worth a second look
WHITESPACE_FIELD_NAMES_IGNORED_2XXis the only rule that trades away a signal CATSwas right to look for. The question that decides it is whether a required field can
be mangled and still yield 2xx — that would be a validation bypass. It cannot today:
all 29 findings mangle an optional field only, zero mangle a required field. The
rule carries an inline note to re-verify that if the request models change.
Deliberately NOT suppressed
Not matching response schemafindings — a CATS defect under research inchore: isolate CATS "Not matching response schema" false-positive trigger and report upstream #637. They are 79% of what remains, but suppressing them would hide genuine schema
regressions in exactly the resources that matter most.
/saml/providers/{idp}/users401s (19) and/me/groups/{id}/members403s (12)— seeding and configuration gaps, not false positives. A rule here would mask real
authorization bugs; the fixtures should be fixed instead.
Also noted
The older
"not in a deleted state"rule is now dead — the server answers"Threat model is not deleted". Rule 69 matches the current wording; the stale rule isleft in place rather than edited, since removing it would shift evaluation order.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WnrVyySuyJFqcMxB8q3pNc