Skip to content

Commit 9c13eaf

Browse files
h0tak88rclaude
andcommitted
fix(apkauditor): nav-deeplink detection missed real targets — use full dex string pool
Validated the new nav_deeplink_ids/nav_deeplink_forced_navigation rule against the two real disclosed reports (BookBeat com.bookbeat.android, BitOasis com.bitoasis) by downloading both APKs (apkeep) and running them through the actual shipped engine. Result: 0 hits on both -- the per-class decompiled-source scan that fed the rule is capped at 1000 classes/dex for performance, and the androidx.navigation library class holding the marker string never falls within that window on real-sized apps. Confirmed via the raw dex string pool that both apps genuinely contain 'android-support-nav:controller:deepLinkIds/Args/Extras' (matching the reports' own claim of verifying against bundled NavController bytecode). Fixed by checking the FULL, uncapped string pool right after dex parsing -- the same substrate detectTrackers() already uses reliably -- instead of relying solely on the capped per-class scan (kept as a secondary path; harmless, occasionally gives a real file/line on smaller apps). Re-validated: both real APKs now produce the consolidated 'nav_deeplink_forced_navigation' finding, correctly naming the exact vulnerable activity from each report (HomeTabBarActivity / MainActivity). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e6193ab commit 9c13eaf

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

internal/api/ui/apkauditor/src/core/engine.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,22 @@ function detectTrackers(strings, files) {
18931893
return [...new Set(TRACKER_SIGS.filter(([, sigs]) => sigs.some(s => combined.includes(s))).map(([name]) => name))];
18941894
}
18951895

1896+
// The Jetpack Navigation library's own deep-link Intent-extra key constants.
1897+
// Present verbatim in the dex string pool whenever an app uses
1898+
// NavController.handleDeepLink() with implicit/explicit deep links — R8/ProGuard
1899+
// minification renames identifiers but does not alter string literal content, so
1900+
// this survives in release builds. Checked against the FULL string pool (not the
1901+
// per-class decompiled-source scan, which is capped at 1000 classes/dex for
1902+
// performance and can miss this since it lives in a third-party library class).
1903+
const NAV_DEEPLINK_MARKERS = [
1904+
'android-support-nav:controller:deepLinkIds',
1905+
'android-support-nav:controller:deepLinkArgs',
1906+
'android-support-nav:controller:deepLinkExtras',
1907+
];
1908+
function detectNavDeepLinkHandling(strings) {
1909+
return strings.some(s => NAV_DEEPLINK_MARKERS.some(m => s.includes(m)));
1910+
}
1911+
18961912
function buildSmaliTree(classes, tree, dexIdx) {
18971913
const limited = classes.slice(0, 5000);
18981914
for (const cls of limited) {
@@ -3019,6 +3035,18 @@ async function analyzeAPK(arrayBuffer, fileMeta, opts) {
30193035
} catch (e) { R.warnings.push(dp + ' parse error: ' + e.message); }
30203036
}
30213037

3038+
// Authoritative, uncapped check for Jetpack Navigation deep-link handling —
3039+
// see detectNavDeepLinkHandling for why this can't rely on the per-class
3040+
// decompiled-source scan below.
3041+
if (detectNavDeepLinkHandling(allDexStrings)) {
3042+
R.findings.push({
3043+
ruleId: 'nav_deeplink_ids', ruleName: 'Jetpack Navigation Deep-Link Intent-Extra Handling', severity: 'issue',
3044+
description: 'App bundles Jetpack Navigation’s Intent-extra deep-link mechanism (NavController.handleDeepLink) — its dex string pool contains the library’s android-support-nav:controller:deepLinkIds/deepLinkArgs/deepLinkExtras key constants. These extras are trusted from whatever Intent reaches the NavHost’s activity. If an exported activity hosts this NavController without stripping these extras first, any co-installed app can force navigation to arbitrary destinations by their numeric resource ID, bypassing intended start-destination gating (e.g. login/profile screens). See "Jetpack Navigation Deep-Link Injection" below if this app also declares an exported activity without a permission.',
3045+
cwe: 'CWE-284', owasp: 'M1', masvs: 'PLATFORM-3',
3046+
file: 'classes.dex (string pool)', line: null, match: 'android-support-nav:controller:deepLinkIds',
3047+
});
3048+
}
3049+
30223050
onProgress(54, 'Parsing resources');
30233051
const arscFile = zip.file('resources.arsc');
30243052
if (arscFile) {

0 commit comments

Comments
 (0)