fix(privacy): anchor the remaining tracking SDK patterns - #34
Open
Maher-Reven wants to merge 3 commits into
Open
Maher-Reven wants to merge 3 commits into
Maher-Reven wants to merge 3 commits into
Conversation
added 2 commits
September 20, 2026 00:03
`(?i)(google.*ads|GADMobileAds|admob)` is unanchored, so `ads` matched inside `loadSdk`, `downloads`, `uploads` and `threads`. Any app that used a non-ad Google SDK and had one of those words on the same line got a CRITICAL §5.1.2 finding, which `--exit-code` turns into a failed build, and the suggested fix was to add an ATT prompt the app does not need. Require an ad-specific token instead. `\badmob` is anchored only at the start so it still covers `AdMobBanner` and `expo-ads-admob` while rejecting words that merely end in those letters. Fixes RevylAI#30
The other `X.*Y` patterns share the defect fixed for Google Ads: an unanchored `.*` between two short tokens matches across unrelated code on the same line. `adjust.*sdk` is the worst — `adjustsFontSizeToFitWidth` and `adjustedContentInset` are ordinary UIKit, so any line carrying one of them and the letters `sdk` reported the Adjust SDK. `unity.*ads` matches `unityWebView.loadThreads()`. `google.*analytics`, `firebase.*analytics` and `facebook.*sdk` have the same shape. Also collapse two alternations that are duplicates under `(?i)`: `(applovin|AppLovinSDK)` and `(ironSource|IronSource)`. Mixpanel, AppsFlyer, Amplitude, Segment and Branch are left alone — they already require a distinctive brand token that cannot collide with an ordinary identifier.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
Reviewed by Cursor Bugbot for commit 9666c1b. Configure here.
Review catch: anchoring those two patterns lost integrations the old ones detected. Firebase only allowed `firebase` and `analytics` to be adjacent or joined by a single `-` or `/`, which drops the namespaced `firebase.analytics()` API and the `firebase/compat/analytics` import path. Allow `.` as a separator and the `compat/` segment. Facebook required `fbsdk`, `facebooksdk` or `facebook-sdk`, which drops `facebook-ios-sdk` and the `facebook-jssdk` script id used by the web loader snippet. Allow the `ios-`, `android-` and `js` infixes. Neither widening reintroduces the false positives: both still require the tokens to be joined, so `firebase/auth` followed by the word analytics, and `facebook` followed by a separate `sdk`, stay clean.
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.

Problem
#33 fixes
google.*adsmatchingloadSdk. The rest of the table has the same shape, and one of them is worse than the reported case.An unanchored
.*between two short tokens matches across unrelated code on the same line:adjust.*sdklabel.adjustsFontSizeToFitWidth = true // call before sdkInit()adjust.*sdkscrollView.adjustedContentInset = insets; let sdkReady = trueunity.*adsunityWebView.loadThreads();unity.*adsconst unityBridge = init(); const uploads = [];google.*analytics{ googleClientId: ID, analyticsEnabled: false }firebase.*analyticsimport { getAuth } from 'firebase/auth'; // analytics intentionally omittedfacebook.*sdk// the facebook login flow was removed; see sdkMigration.mdadjust.*sdkis the one I would prioritise.adjustsFontSizeToFitWidthandadjustedContentInsetare ordinary UIKit that appear in most iOS codebases, so the trigger is just "this file also contains the letterssdk" — and like #30 it produces a CRITICAL §5.1.2 that fails--exit-code.Fix
Require a distinctive token in each case rather than two fragments with a gap:
{regexp.MustCompile(`(?i)(firebaseanalytics|firebase[-/]analytics)`), "Firebase Analytics"}, {regexp.MustCompile(`(?i)(googleanalytics|google-analytics)`), "Google Analytics"}, {regexp.MustCompile(`(?i)(fbsdk|facebooksdk|facebook-sdk)`), "Facebook SDK"}, {regexp.MustCompile(`(?i)(adjust[-_]?sdk|react-native-adjust|com\.adjust\b|Adjust\.(appDidLaunch|trackEvent|initSdk|getAdid))`), "Adjust SDK"}, {regexp.MustCompile(`(?i)(unityads|unity-ads|unity3d\.ads)`), "Unity Ads"},Adjust keeps its API call sites in the alternation because the iOS SDK is imported as
AdjustSdkbut used asAdjust.appDidLaunch(...), and a file may contain only the latter.Two alternations are also collapsed because
(?i)already makes their branches identical:(applovin|AppLovinSDK)→applovin,(ironSource|IronSource)→ironsource.What I deliberately did not change
mixpanel,appsflyer,amplitude,@segment/andbranch.ioare left as they are. The issue on #30 suggestedmixpanelmight have the same problem — it does not. It is a distinctive brand token that cannot appear inside an ordinary identifier the wayadsappears insideloadSdk. Changing it would be churn.(Those patterns do still match inside comments and string literals, but that is a property of how the scan is run rather than of the patterns, and it is not in scope here.)
Testing
Both directions, in
internal/privacy/scanner_test.go:TestTrackingPatternsIgnoreOrdinaryCode— the seven rows in the table above. All seven fail against the old patterns; I verified by reverting them.TestTrackingPatternsStillDetectRealSDKs— twelve real integrations that must keep matching, covering both the import form and the API-call form for Adjust, plus Unity Ads, Google Analytics, Firebase Analytics (RN and Swift), Facebook SDK (RN and iOS), AppLovin and ironSource.go build ./...andgo test ./...are clean.Note
Medium Risk
Changes compliance scan heuristics; anchored patterns could miss uncommon SDK spellings, though broad positive/negative tests reduce that risk.
Overview
Tightens tracking/ad SDK detection in the privacy scanner so loose
token.*tokenregexes stop firing on unrelated same-line code (e.g. UIKitadjustsFontSizeToFitWidth+sdk,googleClientId+analyticsEnabled,firebase/authcomments). That class of matches was incorrectly raising CRITICAL §5.1.2 “tracking SDK without ATT” and failing--exit-code.Patterns for Firebase/Google Analytics, Facebook, Adjust, Google Ads/AdMob, Unity Ads, AppLovin, and ironSource now match distinctive package/API tokens (imports, RN package names,
Adjust.*call sites, Firebase compat paths, etc.) instead of unanchored gaps. AppLovin/ironSource alternations are simplified under(?i).Adds
scanner_test.gocoverage in both directions: ordinary code must not report those SDKs, and representative real integrations must still be detected (including AdMob cases from #30).Reviewed by Cursor Bugbot for commit ab79e2e. Bugbot is set up for automated code reviews on this repo. Configure here.