Releases: f0dders/apk-jtm
Release list
v1.13.1 — Keep the model's thinking out of the report
What's new
A reasoning model's thinking no longer ends up in your report.
Most current local models — including every one recommended in the README — reason before they answer. Ollama returns that pass in a separate field, so it was never seen. LM Studio goes through the OpenAI-compatible path, which has no field for it, so the reasoning arrives inline as <think>…</think> mixed into the report itself.
Nothing downstream could tell it apart from report prose. It was saved into both the HTML and Markdown copies, and the HTML sanitiser then removed the unknown tags while keeping their text — deliberate behaviour, so that a stray <div> costs formatting rather than content — which left an unlabelled monologue with no visible boundary between the model working out and the model concluding.
It is now removed where the report is assembled, before the verdict is read rather than after. That ordering matters twice: a verdict the model tries on mid-reasoning can no longer compete with the one it settled on, and a stream cut off mid-thought is correctly reported as incomplete rather than as a model that declined to rate the app.
Applies to every provider. The live view can still briefly show reasoning as it streams in — suppressing that would mean buffering the whole report, and a screen that shows nothing for thirty seconds looks like a hang.
v1.13.0 — Stop looking broken when you're not
What's new
Reports no longer stop after one sentence when the AI doesn't recognise the app. The prompt told the model to say so "and stop" — and models that followed the instruction ended their whole response, leaving a report the app then flagged as incomplete. An unrecognised app is the normal case for anything internal or unpublished, so this fired constantly.
Launching offline no longer looks like a failure. The launcher printed a pip connection-retry warning for every retry of every package, then launched perfectly anyway. It now checks once whether the package index is reachable and skips the dependency step deliberately, saying so in a single line. A genuine dependency error is still shown in full, and a launcher that can't reach the index no longer stops an app whose dependencies are already installed. Mac, Linux and Windows.
A clean app now actually earns its "Safe to use" badge. The behaviour pill showed Quark-Engine's own threat level — a mechanical weight sum with no idea what the app is — and let it override the badge. Ordinary apps triggered it routinely: across a sample of scans, Briar scored Low Risk on 57 matched patterns while GrapheneOS Camera scored High on 45. The pill now reports how many patterns matched and leaves the judgement to the report.
Local models are tiered properly again. Ollama and LM Studio write model names with a colon (gemma4:12b) while the tier list used hyphens, so every locally-run model was badged "Unknown" and every local report carried a "re-run with a better model" disclaimer. Fixing it also caught a 14B DeepSeek R1 distillation inheriting the 671B model's Frontier rating.
A new default local model — gemma4:12b at 7.6 GB, replacing a 20 GB code-completion model. A general-purpose model reads scan evidence, and admits what it doesn't recognise, better than a coding model does. The README's hardware recommendations have been refreshed to match. Existing configurations are untouched.
Three smaller prompt corrections are in there too: no "Privacy Concerns" section when the scan found no permissions or trackers to discuss, no named malware packers in the instructions (which invited the model to report one the scan never found), and the machine-read verdict must now agree with the verdict written in the summary.
See CHANGELOG.md for the full detail.
v1.12.0 — Trustworthy offline analysis
What's new
If you run APK-JTM offline with a local model, this is the release to update to. Scanning an app the model had never heard of — a private build, an internal tool, a freshly compiled APK — could produce a confident report full of things the scan never found. The clearest example: a "Geographic & Server Analysis" section naming the countries hosting an app's servers, for an app with no network code whatsoever.
The cause was structural. The report asked for a fixed set of sections, but when a scan found nothing for one of them, that section's data was left out of what the AI was given. A required heading with no evidence behind it is an invitation to make something up, and smaller models took it. Sections are now only requested when the scan actually found something, and every category the scan checked is reported even when it came back empty — so "nothing found" is stated as a result rather than left as a gap to fill.
Re-running a report now gives you the same report. No provider was pinning a sampling seed, so every regeneration started from fresh randomness even when nothing about the app had changed. Local models now reproduce their previous report exactly. Hosted providers are best-effort, and current Claude models can't be pinned at all — the app says so rather than implying a guarantee it can't keep.
Reports now open with a Scan evidence panel. Signing status, server locations, packer findings, behaviour patterns, exported components — taken straight from the scan tools and rendered by the app, not written by the AI. These are facts the model can't alter or invent, shown before its interpretation of them. It also tells you when a tool didn't run, which previously looked identical to it running and finding nothing.
Unsigned and debug-signed APKs are now detected and reported. Signing state was never extracted, so an unpublished or freshly built app reached the AI with no sign it wasn't properly signed — while the AI was separately told to be harsher on apps it didn't recognise.
A scanned APK can no longer influence its own verdict. Text taken from the APK went into the AI's instructions unchanged, so a crafted app could embed instructions or forge the machine-readable verdict tag behind the badge you see. That text is now neutralised, fenced off as untrusted, and the verdict is read from the end of the report so a planted tag can't win. Report output is also filtered to safe formatting tags before rendering, closing a route to script running in your browser.
You can now tell the app what you know before scanning. An optional box for describing who built the app and what it's for — most useful for exactly the private and internal builds no model could recognise. It's treated as unverified context that helps judge whether a behaviour is expected, never as proof the app is safe, and it's kept when you re-analyse with a different model.
Also in this release: the prompt now adapts to the model doing the analysis, with smaller models getting the same sections and depth restated as explicit steps (decided by the model, so a large model run offline still gets the full brief); a scan is refused outright rather than quietly producing fiction when the findings won't fit the model's context window; incomplete reports are marked as such instead of appearing merely unrated; and the test suite has grown from 70 to 128.
Full detail in CHANGELOG.md.
v1.11.0 — Report language + offline install
What's new
- Reports can now be written in any language. A new "Report Language" field in ⚙ Settings (default British English) controls the language the AI writes its report in — French, German, Spanish, or anything else, essentially for free since the AI generates the report body itself. Also available via
REPORT_LANGUAGEin config and a matching--languageCLI flag. - Offline install bundle for air-gapped machines.
scripts/build_offline_bundle.shproduces a pre-built archive — vendored dependency wheels, a saved MobSF Docker image, and a Quark-Engine rules snapshot — plus a matching offline launcher (Start - Mac (Offline).command,Start - Linux (Offline).sh). Installs with zero network access; only Python 3.12 and Docker need to already be on the target machine. See docs/OFFLINE.md for details. Windows offline bundles aren't built yet —main.py --report <mobsf.json>remains a fully offline workaround there.
See CHANGELOG.md for full details.
v1.10.1 — Progress view bugfix
What's new
Fixed a confusing progress-view bug: starting a new scan could briefly show "Analysis complete" and a "your report is ready" message left over from the previous scan, while the new scan's stages were genuinely still spinning underneath. The heading, subtitle, AI-output label, and View Report button now reset properly at the start of every scan, so the progress view always reflects what's actually happening.
No other behaviour changes in this release.
v1.10.0 — Security fixes, reliability hardening & dark-mode reports
What's new
Implements a full security/reliability audit backlog: nine bugs fixed, one offline-privacy gap closed, and a few UI improvements.
Security: a stored XSS vulnerability in the history and version-compare views — app names, versions, and AI summaries were written into the page unescaped and could run arbitrary script if a scanned APK's manifest (or the AI's own output) contained crafted HTML. All untrusted fields are now escaped.
Also fixed: a false "0/100 — Critical Risk" on JSON-uploaded reports, an AI-analysis timeout that could kill slow local models mid-response, a rate-limit retry message that could corrupt a saved report's verdict, a memory leak on long-running instances, a path-traversal gap on the report endpoint, unbounded upload memory usage, and a model-tier misclassification for cheap model variants.
Improvements: generated reports now support dark mode, icon-only buttons have accessible labels, truncated domain lists say so, and the update check no longer phones home when running fully offline (Ollama/LM Studio).
15 new tests added (68 total, all passing).
v1.9.4 — CONTRIBUTING.md
What's new
Added CONTRIBUTING.md following a review of this project's git practices against industry standards.
The review found: tagging, releases, and CHANGELOG discipline are already solid. Direct commits to `main` are a deliberate, legitimate choice for a solo-maintained project — not something that needed fixing. The actual gap was that issue templates invited bug reports and feature requests, but nothing told an outside contributor how to submit an actual code change.
CONTRIBUTING.md now covers: fork/branch/PR process, running the test suite first, updating CHANGELOG under `[Unreleased]`, code style expectations, and licensing (GPL v3).
Also added a "Contributing" section to the README linking both CONTRIBUTING.md and SECURITY.md (which wasn't linked from the README before).
See CHANGELOG.md for full history.
v1.9.3 — Gemini SDK migration + README cleanup
What's new
Migrated off the deprecated Gemini SDK
Google deprecated `google-generativeai` in favour of a new unified SDK, `google-genai`. GeminiProvider now uses `genai.Client(...).models.generate_content_stream(...)` — same streaming interface, no behaviour change for users.
README fixes
- Acknowledgements section's Google SDK link now points at the SDK actually installed (`googleapis/python-genai`) rather than the deprecated package's repo
- "Compare versions" description now mentions Quark-Engine threat-level diffing — the feature has done this since v1.7.0 but the docs never caught up
See CHANGELOG.md for full history.
v1.9.2 — README fix
Fixed
- README intro paragraph still described the app as "MobSF + APKiD" only — missed updating when Quark-Engine was added in v1.7.0. Now correctly names all three analysis engines.
See CHANGELOG.md for full history.
v1.9.1 — Acknowledgements
What's new
Acknowledgements section added to the README
APK-JTM is an orchestration layer over several open-source security tools — this release properly credits them:
- Core analysis engines: MobSF, APKiD, Quark-Engine (all GPL-3.0/GPL-compatible)
- Supporting libraries: FastAPI, Uvicorn, the AI provider SDKs, and others — each with a verified licence
Licences were confirmed against actual package metadata rather than assumed, which also caught that `google-generativeai` (the package this app depends on) is now deprecated by Google in favour of `google-genai` — the README now links to the correct (deprecated but actually-installed) repo.
See CHANGELOG.md for full history.