Bug
In check-bugreport / check-androidqf runs, dumpsys_receivers_detected.json reports a CRITICAL match:
{
"message": "Found a known suspicious receiver with name \"com.android.phone/com.android.services.telephony.sip.SipIncomingCallReceiver\" matching indicators from \"TheOneSpy\"",
"event": {"package_name": "com.android.phone",
"receiver": "com.android.phone/com.android.services.telephony.sip.SipIncomingCallReceiver"},
"matched_indicator": {"value": "com.android.services", "type": "app_ids", "name": "TheOneSpy"}
}
The matched com.android.phone is the AOSP SIP telephony receiver, not TheOneSpy. The indicator value com.android.services is a real TheOneSpy masquerade package id (AssoEchap data is correct) — but it appears here only as a substring of com.android.services.telephony.sip.SipIncomingCallReceiver inside system package com.android.phone.
Reproduces on MVT 2026.5.12 against any device still shipping SIP telephony in com.android.phone (Android ≤ 13 stock, plus OEM ROMs that retained SIP after the API 34 removal — SIP was deprecated in API 31 and removed in API 34). Verified on HUAWEI STK-L21 / EMUI 10.
Where
Introduced by #721 (merged 2026-01-10). Two files:
src/mvt/android/modules/bugreport/dumpsys_receivers.py:38-52 — the only caller of check_receiver_prefix in the codebase, and the only Android module that compares an indicator against the full package/class string instead of package_name:
receiver_name = self.results[result][0]["receiver"]
ioc_match = self.indicators.check_receiver_prefix(receiver_name)
src/mvt/common/indicators.py:730-751 — unanchored substring containment, despite the name check_receiver_prefix:
for ioc in self.get_iocs("app_ids"):
if ioc.value.lower() in receiver_name.lower(): # ← unanchored
return IndicatorMatch(ioc=ioc, ...)
Every other Android artifact (≈14 callsites) uses check_app_id (indicators.py:709-728), which does exact equality against package_name. That code path would not produce this FP.
Notably, the sibling artifact module src/mvt/android/artifacts/dumpsys_receivers.py:53 already does the right thing — it calls check_app_id(receiver["package_name"]). Only the bugreport wrapper in modules/bugreport/dumpsys_receivers.py was switched to the new check_receiver_prefix path in #721, so the two receiver-matching paths in the codebase now disagree.
Fix
Smallest change — drop check_receiver_prefix and call check_app_id on the package portion:
# modules/bugreport/dumpsys_receivers.py
package_name = receiver_name.split("/", 1)[0]
ioc_match = self.indicators.check_app_id(package_name)
If checking class paths is intentional (the goal of #721), anchor on a namespace boundary instead of using in:
def check_receiver_prefix(self, receiver_name: str):
if not receiver_name:
return None
lower = receiver_name.lower()
pkg = lower.split("/", 1)[0]
for ioc in self.get_iocs("app_ids"):
v = ioc.value.lower()
if pkg == v or lower.startswith(v + "."):
return IndicatorMatch(ioc=ioc, ...)
return None
Under either fix, the canonical FP disappears (com.android.phone ≠ com.android.services, and com.android.services is not at a namespace boundary inside the SIP class path), while a real com.android.services/... receiver still matches.
Regression test:
def test_check_receiver_prefix_does_not_match_aosp_namespace_substring():
ind = ... # TheOneSpy / app_ids: ["com.android.services"]
assert ind.check_receiver_prefix(
"com.android.phone/com.android.services.telephony.sip.SipIncomingCallReceiver"
) is None
assert ind.check_receiver_prefix(
"com.android.services/com.example.SomeReceiver"
) is not None
Happy to send a PR for option 1 or 2 — preference welcome.
Bug
In
check-bugreport/check-androidqfruns,dumpsys_receivers_detected.jsonreports a CRITICAL match:{ "message": "Found a known suspicious receiver with name \"com.android.phone/com.android.services.telephony.sip.SipIncomingCallReceiver\" matching indicators from \"TheOneSpy\"", "event": {"package_name": "com.android.phone", "receiver": "com.android.phone/com.android.services.telephony.sip.SipIncomingCallReceiver"}, "matched_indicator": {"value": "com.android.services", "type": "app_ids", "name": "TheOneSpy"} }The matched
com.android.phoneis the AOSP SIP telephony receiver, not TheOneSpy. The indicator valuecom.android.servicesis a real TheOneSpy masquerade package id (AssoEchap data is correct) — but it appears here only as a substring ofcom.android.services.telephony.sip.SipIncomingCallReceiverinside system packagecom.android.phone.Reproduces on MVT
2026.5.12against any device still shipping SIP telephony incom.android.phone(Android ≤ 13 stock, plus OEM ROMs that retained SIP after the API 34 removal — SIP was deprecated in API 31 and removed in API 34). Verified on HUAWEI STK-L21 / EMUI 10.Where
Introduced by #721 (merged 2026-01-10). Two files:
src/mvt/android/modules/bugreport/dumpsys_receivers.py:38-52— the only caller ofcheck_receiver_prefixin the codebase, and the only Android module that compares an indicator against the fullpackage/classstring instead ofpackage_name:src/mvt/common/indicators.py:730-751— unanchored substring containment, despite the namecheck_receiver_prefix:Every other Android artifact (≈14 callsites) uses
check_app_id(indicators.py:709-728), which does exact equality againstpackage_name. That code path would not produce this FP.Notably, the sibling artifact module
src/mvt/android/artifacts/dumpsys_receivers.py:53already does the right thing — it callscheck_app_id(receiver["package_name"]). Only the bugreport wrapper inmodules/bugreport/dumpsys_receivers.pywas switched to the newcheck_receiver_prefixpath in #721, so the two receiver-matching paths in the codebase now disagree.Fix
Smallest change — drop
check_receiver_prefixand callcheck_app_idon the package portion:If checking class paths is intentional (the goal of #721), anchor on a namespace boundary instead of using
in:Under either fix, the canonical FP disappears (
com.android.phone≠com.android.services, andcom.android.servicesis not at a namespace boundary inside the SIP class path), while a realcom.android.services/...receiver still matches.Regression test:
Happy to send a PR for option 1 or 2 — preference welcome.