Repository navigation
0.5.0: deep scan, and a report that opens with what it could not see - #5
Merged
Merged
Conversation
The whole release serves one directive: never wrong, and as invasive as an unprivileged app can be. Depth and honesty ship together, because depth without the could-not-check list would just be a longer way to imply a verdict. Bridge: every surface Android exposes to a sideloaded scanner is now read, each one wrapped so a single failure cannot kill the scan, and each reporting ok or unavailable with the concrete reason. New reads: accessibility capability detail from AccessibilityManager (the settings string stays as a cross-check), real runtime permission grants per app, manifest facts (foreground service types, boot receivers, targetSdk, lastUpdateTime, sharedUserId, debuggable), device admin policy bits via DeviceAdminInfo, enabled IMEs, user-added CA certificates, default SMS and dialer plus best-effort assistant, battery exemptions, device and profile owners by per-package probe, ADB and developer switches, install source v2 with the initiating package, and VpnService declarers. Appop-backed specials are reported as declared only, since the GRANTED bit lies for those. Three grant lists Android reserves for privileged apps are hardcoded unavailable, so the report says so on every single scan instead of staying quiet. Analyzer: matches are tiered by evidence. Certificate match, cert plus package, package-only with softened wording that says the cert did not corroborate, and prefix, which never surfaces at all without a corroborating power. Watchware (parental monitoring) is a separate top-level dataset key, a separate matcher, a separate output array, and a separate renderer, so no code path can hand a Family Safety install stalkerware wording. The disguise rule is anchored on the installer, not the name: system-style prefix plus no system record plus a non-Play installer, because a Play-updated Google app is non-system too and must never fire it. Every finding carries its headline template, raw evidence, the rule id that fired, install provenance, and what the app can do right now from the actual grant table; the UI renders findings, it does not write them. Dataset: fetch-indicators.py pins the exact upstream commit, ingests watchware.yaml alongside ioc.yaml, validates certificate and package shapes with a hard non-zero exit, prints an added and removed diff against the committed data, and refuses a family-count swing over 20 percent without --force. The bundled data records the pinned commit (a04c5c1958bf) and now carries aliases and certificate organizations for recognition copy. NOTICE.md links the CC-BY 4.0 text and states the subset is filtered and reformatted, which the license asks for and the old notice skipped. Tests: a labeled benign corpus (TalkBack, VoiceAccess, LastPass, Bitwarden, Find My Device, Intune, Family Link, Wellbeing, Messenger, Google Messages, a Play-updated Google app) holds the false-accusation floor at zero stalkerware-tier findings; the full IOC corpus must match 100 percent at the right tier; spoof twins (wrong-cert LastPass, a stalkerware cert on a novel package, a non-system TalkBack clone, a watchware package) must diverge from their benign twins, so a dead rule fails the build instead of passing quietly; the three privileged surfaces must appear in could-not-check on every scan shape; and the fetch validators must reject malformed data with a non-zero exit. One honest note: Family Link is not on the upstream watchware list, so it cannot land the dual-use track from data. The test asserts the part that protects people, that it never lands a stalkerware tier, and Kaspersky Safe Kids exercises the dual-use assertion instead. English and Spanish stay at full parity (246 strings). versionCode 500. No new permissions: the manifest is still QUERY_ALL_PACKAGES and nothing else. ACCESS_NETWORK_STATE stayed out on purpose; VPN presence detection would need it, so the VPN surface ships as the declarer list plus best-effort settings reads instead. The disguise rule needs more than a non-Play installer. The Galaxy Store carries real com.samsung apps and enterprise setups push real com.android ones, so a system-looking name only gets a card when it also hides from the launcher, holds a watching power, or starts on boot.
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.
The whole release serves one directive: never wrong, and as invasive as
an unprivileged app can be. Depth and honesty ship together, because
depth without the could-not-check list would just be a longer way to
imply a verdict.
Bridge: every surface Android exposes to a sideloaded scanner is now
read, each one wrapped so a single failure cannot kill the scan, and
each reporting ok or unavailable with the concrete reason. New reads:
accessibility capability detail from AccessibilityManager (the settings
string stays as a cross-check), real runtime permission grants per app,
manifest facts (foreground service types, boot receivers, targetSdk,
lastUpdateTime, sharedUserId, debuggable), device admin policy bits via
DeviceAdminInfo, enabled IMEs, user-added CA certificates, default SMS
and dialer plus best-effort assistant, battery exemptions, device and
profile owners by per-package probe, ADB and developer switches,
install source v2 with the initiating package, and VpnService
declarers. Appop-backed specials are reported as declared only, since
the GRANTED bit lies for those. Three grant lists Android reserves for
privileged apps are hardcoded unavailable, so the report says so on
every single scan instead of staying quiet.
Analyzer: matches are tiered by evidence. Certificate match, cert plus
package, package-only with softened wording that says the cert did not
corroborate, and prefix, which never surfaces at all without a
corroborating power. Watchware (parental monitoring) is a separate
top-level dataset key, a separate matcher, a separate output array, and
a separate renderer, so no code path can hand a Family Safety install
stalkerware wording. The disguise rule is anchored on the installer,
not the name: system-style prefix plus no system record plus a non-Play
installer, because a Play-updated Google app is non-system too and must
never fire it. Every finding carries its headline template, raw
evidence, the rule id that fired, install provenance, and what the app
can do right now from the actual grant table; the UI renders findings,
it does not write them.
Dataset: fetch-indicators.py pins the exact upstream commit, ingests
watchware.yaml alongside ioc.yaml, validates certificate and package
shapes with a hard non-zero exit, prints an added and removed diff
against the committed data, and refuses a family-count swing over 20
percent without --force. The bundled data records the pinned commit
(a04c5c1958bf) and now carries aliases and certificate organizations
for recognition copy. NOTICE.md links the CC-BY 4.0 text and states the
subset is filtered and reformatted, which the license asks for and the
old notice skipped.
Tests: a labeled benign corpus (TalkBack, VoiceAccess, LastPass,
Bitwarden, Find My Device, Intune, Family Link, Wellbeing, Messenger,
Google Messages, a Play-updated Google app) holds the false-accusation
floor at zero stalkerware-tier findings; the full IOC corpus must match
100 percent at the right tier; spoof twins (wrong-cert LastPass, a
stalkerware cert on a novel package, a non-system TalkBack clone, a
watchware package) must diverge from their benign twins, so a dead rule
fails the build instead of passing quietly; the three privileged
surfaces must appear in could-not-check on every scan shape; and the
fetch validators must reject malformed data with a non-zero exit.
One honest note: Family Link is not on the upstream watchware list, so
it cannot land the dual-use track from data. The test asserts the part
that protects people, that it never lands a stalkerware tier, and
Kaspersky Safe Kids exercises the dual-use assertion instead.