Port 3 BEC-relevant Sagan Cloud rules to legacy (skip BAV2ROPC) - #706
Merged
CGoggins56 merged 1 commit intoAug 28, 2026
Conversation
Adds ungated legacy analogues for three low-noise sagan-cloud-rules BEC detections that legacy currently only covers geo/bluedot-gated or not at all: - sid:5017957/5017958 (msapi-azuread.rules) -- ungated illicit OAuth consent-grant / delegated-permission-grant detection, porting cloud 600548/600599. Legacy's existing consent rules (5004804/5004837) only fire from outside HOME_COUNTRY or a Bluedot-listed IP, so a same- country, clean-IP grant was invisible. Uses plain content/pcre instead of json_content for the ModifiedProperties scope check, since ModifiedProperties is a JSON array and legacy never expands arrays via json_content/json_map. - sid:5017959/5017960 (new msapi-microsoftteams.rules) -- Teams archive-file / multi-file exfil to foreign tenant users, porting cloud 6005331/6005332. json_content key truncated to the engine's 31-char limit (.ParticipantInfo.HasForeignTena) per the documented JSON_MAX_KEY_SIZE fix pattern. Cloud's array-length/ChatThreadId rate logic can't be reproduced directly (no array counting, no arbitrary track_by field), so this substitutes a by_username rate as a proxy -- flagged inline as an approximation, not a literal port. Deliberately excludes cloud 6005257 (Legacy Auth / BAV2ROPC): Grafana alert volume showed 2,290 hits YTD 2026 across 17 tenants, the noisiest of the four candidates evaluated -- needs a suppression pass before porting, not a straight 1:1 port. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RHYEbkU9keVovW9UAACgsX
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.
Summary
sagan-cloud-rulesBEC/O365 detections to legacy.rules, identified via a legacy-vs-cloud BEC coverage comparison and validated for noise against Grafana alert history (YTD 2026, all customers):5017957/5017958(msapi-azuread.rules) — ungated illicit OAuth consent-grant / delegated-permission-grant detection, porting cloud600548/600599. Legacy's existing consent rules (5004804/5004837) only fire from outsideHOME_COUNTRYor a Bluedot-listed IP — a same-country, clean-IP grant was previously invisible.5017959/5017960(newmsapi-microsoftteams.rules) — Teams archive-file / multi-file exfil to foreign tenant users, porting cloud6005331/6005332.6005257(Legacy Auth / BAV2ROPC) — Grafana showed 2,290 hits YTD across 17 tenants, by far the noisiest of the four candidates. Needs a suppression pass before it's portable, not a straight 1:1 port.Known limitations (flagged inline in the rule comments)
ModifiedProperties(consent rules) andMessageFiles(Teams rules) are JSON arrays in the source UAL records. The legacy engine never expands JSON arrays viajson_content/json_map, so the scope/file checks use plaincontent/pcresubstring matching on the raw record instead of a structured field path — same technique already used elsewhere inmsapi-azuread.rulesfor array-nested fields (e.g. the named-role rules)..ParticipantInfo.HasForeignTenantUsersis 38 characters, over the engine's 31-char key-truncation limit (JSON_MAX_KEY_SIZE=32), so both Teams rules use the truncated key.ParticipantInfo.HasForeignTena, following the established fix pattern fromsagan-rules#704.MessageFiles[]≥6) andChatThreadId-based rate limiting can't be reproduced in legacy (no array counting, no arbitrarytrack_byfield), so both Teams rules substitute aby_usernamerate as an approximation — flagged as such, not a literal port.Test plan
python3/ repo lint check for duplicate SIDs and rule syntax (ran locally — no collisions against existingalertlines)ConsentAction.Permissions/DelegatedPermissionGrant.Scope/MessageFilesliteral substrings actually appear as expected in a live UAL record for this ingest pipeline🤖 Generated with Claude Code
https://claude.ai/code/session_01RHYEbkU9keVovW9UAACgsX