android_kotlin_hiddenui fires as Critical/ERROR on any View.GONE/INVISIBLE, not just sensitive views — massive false-positive rate
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 787
- Forks
- 125
- PR merge metrics
- No merged PRs in 30d
Description
Title: android_kotlin_hiddenui fires as Critical/ERROR on any View.GONE/INVISIBLE, not just sensitive views — massive false-positive rate
Rule in question
https://github.com/MobSF/mobsfscan/blob/main/mobsfscan/rules/semgrep/kotlin/android.yaml#L2
id: android_kotlin_hiddenui
...
message: Hidden elements in view can be used to hide data from user. But this data can be leaked.
severity: ERROR
metadata:
cwe: cwe-919
owasp-mobile: m1
masvs: storage-7
What the rule matches
$V.visibility = View.GONE, $V.visibility = View.INVISIBLE, the ternary variants, and $V.setVisibility(View.GONE|INVISIBLE) — for any $V. There's no constraint on what the view is or what it contains.
Why this is a problem
The underlying concern (CWE-919 / MASVS-STORAGE-7) is real but narrow: a view holding sensitive data (a PIN entry, a masked card number, an auth token displayed somewhere) that's merely hidden with GONE/INVISIBLE is still present in the view hierarchy and can be read back via accessibility services, uiautomator dumps, or similar tooling, even though a human eye can't see it.
But View.GONE/INVISIBLE is also just... how Android apps show and hide UI. Toggling visibility on dividers, chevrons, snackbars, tutorial overlays, and widget buttons is one of the most common UI operations in any nontrivial app. Because the pattern has no data-flow/naming constraint, it fires identically on:
// hides a layout divider — no data involved
headerDivider?.visibility = View.INVISIBLE
// hides a decorative chevron icon depending on form state
chevron.visibility = View.INVISIBLE
// hides a snackbar view before/after animating it in
snackBarView.visibility = View.INVISIBLE
as it would on an actual hidden sensitive field. In a real-world Android codebase we scanned, 100% of the android_kotlin_hiddenui hits were benign visibility toggles (icons, dividers, snackbars, home-screen widget buttons) — zero were sensitive-data related — yet every one is reported as Critical/ERROR severity, identical to genuine hardcoded-secret or world-writable-file findings. This makes the rule effectively unusable for triage: it either gets ignored wholesale or burns significant analyst time confirming non-issues.
Comparison to other rules in the same file
Two other rules in this exact file already solve this problem correctly by scoping to sensitive names via metavariable-regex:
android_kotlin_hardcoded— restricts to variables matching(?i)^(?:password|pass|username|secret|key|(?:api|secret|private|access|encryption|auth)_?key)$android_kotlin_sensitive_input_keyboard_cache— restricts to fields matching(?i).*(?:password|passcode|pin|secret|otp|token).*android_kotlin_sensitive_notification— restricts notification content to the same sensitive-name pattern
android_kotlin_hiddenui is the outlier: it's the only "sensitive data exposure via UI" rule in the file with no such scoping.
There is no legitimate code change that satisfies this rule
We looked at what it would actually take to make a flagged line pass this check as currently written, without suppressing the finding. Because the pattern is a pure literal-token match (not a data-flow or type-aware check), there are exactly two ways to make it stop firing on a given line, and neither is a real remediation:
-
Replace the named constant with its raw integer value.
View.INVISIBLEis4andView.GONEis8in the Android SDK, so:// before — matches android_kotlin_hiddenui headerDivider?.visibility = View.INVISIBLE // after — does not match; identical behavior at runtime headerDivider?.visibility = 4 // View.INVISIBLEThis compiles and behaves identically. The view is hidden in exactly the same way, exactly as "leakable" by whatever mechanism the rule is theoretically worried about, as before. The only thing that changed is that the scanner's string match no longer applies. This is textbook scanner evasion, not a fix — arguably it makes the code worse (magic number instead of the SDK constant) for zero security benefit.
-
Delete the visibility-toggle code entirely. This passes the check but removes the underlying UI feature (the divider/chevron/snackbar would always be shown), i.e. a functional regression traded for a clean scan.
There is no third option where a code change makes the app meaningfully more secure and the rule stops firing as a result, because the rule isn't measuring anything about sensitive data handling — it's matching on the presence of an API call. For this specific rule, "the scan is green" and "the code is secure" are uncorrelated, so gating CI/release on it produces either permanent noise or incentivizes exactly the kind of cosmetic rewrite in option 1 above. That's arguably the strongest argument for fixing the rule itself rather than asking downstream projects to work around it.
Suggested fix
Apply the same metavariable-regex approach already used elsewhere in this file, constraining $V (or the receiver's declared/inferred name) to sensitive-sounding identifiers, e.g.:
metavariable-regex:
metavariable: $V
regex: "(?i).*(?:password|passcode|pin|cvv|card(?:num|number)?|secret|token|otp|auth).*"
This alone would eliminate the vast majority of false positives while preserving detection for the actual risk scenario (hiding a sensitive-data view instead of clearing/removing it).
As a secondary/complementary option, consider dropping severity from ERROR to WARNING/INFO given how broad and heuristic the current pattern is, similar to how other high-noise SAST checks are often kept at lower severity until a stronger signal (sensitive naming, adjacency to a password/PIN EditText, etc.) is present.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in rules/semgrep/kotlin/android.yaml at android_kotlin_hiddenui and compare its metavariable-regex scoping with the neighboring sensitive rules. Check the rule against the benign visibility examples and sensitive-looking view names described in the issue. Done means common non-sensitive toggles no longer report while the stated sensitive-view case remains covered, with the severity choice resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- mobile-dev, security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100