Skip to content

v0.3.0 — corpus-driven detectors

Choose a tag to compare

@anasfik anasfik released this 30 Oct 20:24
· 21 commits to main since this release

On-device Flutter app research workbench. Offline, no root, no INTERNET permission.

What changed in 0.3.0

This release is the result of auditing 26 real release-mode Flutter APKs (Conduit,
Anx Reader, AppFlowy, Gopeed, PiliPala, Kazumi, Finamp, Musify, namida, Cashew,
AuthPass, KitchenOwl, venera, jasmine, Openlib, BeeCount, OpenNutriTracker,
Harmony Music, BloomeeTunes, Echo-Loop, Ghosten Player, oneAnime, PixEz, Spotube,
FluffyChat, Primal) against what the tool reported, then closing the measured gaps.

AI provider inventory
A single lumped "OpenAI/LLM" rule became ~25 named providers, each matched by
host, DEX descriptor or pub package: OpenAI, Anthropic, Google Gemini, OpenRouter,
DeepSeek, Groq, Mistral, Cohere, Together, Fireworks, Perplexity, xAI, HuggingFace,
Replicate, AWS Bedrock, DashScope/Qwen, Moonshot, Zhipu GLM, MiniMax, ElevenLabs,
Stability, LangChain, MediaPipe GenAI, LiteRT — plus localhost:11434 (Ollama),
localhost:1234 (LM Studio) and ComfyUI :8188, because an app that talks to a
local model is a real and easily missed case.

The bug that hid them
Host harvesting only ran on strings containing ://. A Dart AOT snapshot stores a
provider base URL bare (api.anthropic.com on its own), so those hosts were never
collected. A closed provider-domain matcher with a lookbehind now catches them
(myopenai.com is not openai.com). Conduit went from 4 to 17 reported
providers — matching the 22 endpoints measured in its APK on a desktop.

Third-party SDKs
35 services → ~135, across four independent evidence classes (bundled file, DEX
descriptor, pub package, network host): ad networks and mediation, attribution,
engagement, identity (Auth0, Clerk, Appwrite, Stytch, WorkOS, Okta, Keycloak),
realtime (Agora, LiveKit, Sendbird, Stream, Jitsi, Daily, Vonage, MQTT), payments
(PayPal, Braintree, Paddle, LemonSqueezy, Razorpay, Adyen, Play Integrity),
backends (PocketBase, Nhost, Parse, GraphQL, gRPC, Vercel, Railway, Render, Fly,
Heroku, DigitalOcean, B2), vector/search (Pinecone, Qdrant, Weaviate, Typesense,
Meilisearch, Elastic), and on-device HTTP servers (shelf, dart_frog, dhttpd).

More secret families
25 new rules: Anthropic, OpenAI project keys, Groq, HuggingFace, Replicate,
OpenRouter, xAI, Fireworks, Postmark, Mailgun, Azure AccountKey=, GCP service
account JSON, DigitalOcean, GitHub PAT, GitLab, npm, Docker, Postman, Airtable,
Notion, Linear, Slack and Discord webhooks, bearer JWTs, AES/ECB. Root cause fixed
along the way: rule gates are matched against lowercased text, so any uppercase
gate (AccountKey=, PMAK-) made the rule unreachable.

Bundled asset inventory
New findings from file names alone, so nothing secret is read to produce them:
WEB-PAYLOAD (bundled HTML/JS rendered in a WebView, plus script count),
SDK-MARKER (root billing.properties, play-services-*.properties,
transport-*.properties, firebase-encoders*.properties name the SDK without any
DEX parsing), AST-CONFIG (bundled config, key material, databases).

Exact dependency versions when available
When an APK still ships assets/flutter_assets/pubspec.yaml the report now lists
real dependency names and constraints (FLUT-PUBSPEC). Measured: that file is
present in only 1 of 26 release APKs, so it is a bonus signal — the NOTICES.Z /
package: URI recovery stays the primary path.

Requirements

Android 8.0+ (API 26). Sideload the signed APK; no Play Services needed.

Verification

239 unit tests, 0 failures. Device-verified on a physical Redmi Note 9 Pro
(LineageOS, API 35) against Conduit: 28 third-party services, 17 AI providers,
23 provider hosts, WEB-PAYLOAD 2 pages / 7 scripts, SDK-MARKER 4,
AST-CONFIG 17, atomic report write clean.

This release is signed with the same certificate as 0.2.0, so it updates an
existing install in place and keeps stored reports.

Known limits

  • A scan of a large APK is slow: Conduit (~38 MB libapp.so) takes about five
    minutes, ~2m45s of it in the single-threaded native string sweep, and the native
    stage reports one progress line for all libraries. Per-library progress and a
    cheaper sweep for very large snapshots are the next performance items.
  • Some provider hosts are harvested but not yet attributed to a named service
    (api.cerebras.ai, api.novita.ai, api.poe.com, open.bigmodel.cn,
    dashscope.aliyuncs.com), so they appear in the host list rather than as a
    provider row.
  • Ad, attribution, auth, realtime, payment, backend and vector-store detectors are
    coverage, not corpus findings: none of those matched in the 26 apps studied.
  • A matched host or key proves a string is in the APK, not that it is called,
    reachable, or still valid.
  • Candidate routes are recovered strings, not a navigation path. libapp.so is
    AOT machine code: strings, symbols and routes, not decompiled Dart. AABs are not
    supported. Signature verification is structural, not a full apksigner check.