[GH-ISSUE #6819] [Bug] Android package summaries drop fields when the Android namespace uses another prefix #4165

Closed
opened 2026-10-31 00:47:21 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6819

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

Source-only finding: inspect_android_package can report null version/SDK fields and an empty permission array when a manifest binds the Android namespace to a instead of android. The attributes remain in the retained XML. The audited producer matches literal android: spellings; REA forwards that summary and turns empty scalar strings into null.

A local boundary probe exercised the real REA adapter with results calculated using the producer's verbatim regex patterns. The android control preserved all fields; changing only the prefix to a lost all five Android fields. This is not a real APK/JADX reproduction: the Kotlin parser and JVM were not executed.

Reproduction

From the source checkout, save this reduced boundary probe as /tmp/rea-manifest-prefix.mts and run REA_ROOT="$PWD" node_modules/.bin/tsx /tmp/rea-manifest-prefix.mts. It deliberately simulates the pinned producer using its published expressions; it does not claim to execute that producer.

import { pathToFileURL } from 'node:url';
const { analyzeJadxRequest } = await import(pathToFileURL(
  `${process.env.REA_ROOT}/src/android/JadxAnalysis.ts`).href);
const engine = {
  name: 'jadx', version: '0.7.1', artifact_sha256: 'a'.repeat(64),
  source_revision: null, worker_count: 1, heap_limit_mib: null,
};
for (const prefix of ['android', 'a']) {
  const xml = `<manifest xmlns:${prefix}="http://schemas.android.com/apk/res/android" package="org.example.fixture" ${prefix}:versionName="one" ${prefix}:versionCode="7"><uses-sdk ${prefix}:minSdkVersion="23" ${prefix}:targetSdkVersion="35"/><uses-permission ${prefix}:name="org.example.fixture.MARKER"/><application/></manifest>`;
  const app = {
    package: /<manifest\b[^>]*\bpackage="([^"]+)"/u.exec(xml)?.[1] ?? '',
    version_name: /android:versionName="([^"]+)"/u.exec(xml)?.[1] ?? '',
    version_code: /android:versionCode="([^"]+)"/u.exec(xml)?.[1] ?? '',
    min_sdk: /android:minSdkVersion="([^"]+)"/u.exec(xml)?.[1] ?? '',
    target_sdk: /android:targetSdkVersion="([^"]+)"/u.exec(xml)?.[1] ?? '',
    permissions: Array.from(xml.matchAll(/<uses-permission\b[^>]*android:name="([^"]+)"/gu), m => m[1]),
  };
  const result = await analyzeJadxRequest({
    json: async () => app, text: async () => xml,
    listClasses: async () => { throw new Error('unused'); },
  }, { operation: 'inspect_android_package', input: { path: '/fixture.apk' } }, {
    state: 'LOADED', apk_path: '/fixture.apk', class_count: 0,
    resource_count: 1, threads: 1, resources: 'full',
  }, engine);
  console.log(JSON.stringify({prefix, result}));
}

The retained rerunnable probe used the same adapter and extracted these expressions directly from the pinned Kotlin source. Each prefix was examined once before writing this report.

Expected behavior

Equivalent namespace bindings should produce equivalent manifest summaries: version name one, version code 7, min SDK 23, target SDK 35, and the declared marker permission. XML expanded names use namespace URI plus local name; the prefix is a placeholder.

This is reachable in the producing decoder by source inspection: JADX 1.5.6 preserves a declared namespace prefix and uses that mapping to print attributes. It generates the conventional android prefix only when a mapping is absent. No APK decoder run was performed for this report.

Impact and scope

The structured package summary can lose declared version, SDK and permission facts for this namespace representation. This is static metadata correctness, with no execution or authenticity claim. The boundary probe retains the complete XML, so inspecting that XML recovers the facts. Real APK frequency and end-to-end behavior remain NOT_ENOUGH_INFO: no JDK/JADX engine was available for this pass.

REA version

6.7.0, source e2efd10b70a2b5f15a7ac1b5a457a9a1dbcab4d4.

Runtime and platform

Boundary probe: Node.js v24.22.1, Linux 7.2.8-9-omarchy x86_64. No Java runtime, Android SDK, device or APK execution.

Target and artifact context

Two benign authored XML manifests differing only in namespace prefix, plus simulated upstream summaries. No actual APK or private target data.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Selected fields from the observed adapter output:

prefix   version_name version_code min_sdk target_sdk permissions
android  one          7            23      35         [org.example.fixture.MARKER]
a        null         null         null    null       []

Both outputs retain their respective full manifest with status: complete.

Typed outcome or recovery expected

Preserve the declared scalar fields and permission names independent of prefix spelling, or explicitly report that the summary cannot be interpreted. Retain the XML evidence.

Analysis or suspected cause

Source-derived: the pinned producer's literal-prefix regexes omit these attributes; REA accepts that summary without namespace-aware interpretation. The decoder source supports prefix preservation, but the complete binary-XML path remains unverified.

Additional context

Open and closed searches for JADX namespace, manifest prefix, manifest summary and namespace Android found no matching report; the supplied 1,067 open issue bodies were also searched. No known-good release was established. A proposed next check is to compile an ordinary manifest using the a prefix and run the real pinned JAR; that check was not run.

Triage assessment

  • Impact level: P2
  • Assessment status: provisional
  • Impact basis: The source and boundary probe support loss of structured manifest facts for equivalent namespace bindings; a real binary-XML/JADX run is missing, so end-to-end reach remains provisional.
  • Workaround status: available
  • Workaround basis: The executed boundary probe retains the complete manifest text with every affected value, allowing direct inspection of the same evidence.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6819 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior Source-only finding: `inspect_android_package` can report null version/SDK fields and an empty permission array when a manifest binds the Android namespace to `a` instead of `android`. The attributes remain in the retained XML. The audited producer matches literal `android:` spellings; REA forwards that summary and turns empty scalar strings into null. A local boundary probe exercised the real REA adapter with results calculated using the producer's verbatim regex patterns. The `android` control preserved all fields; changing only the prefix to `a` lost all five Android fields. This is not a real APK/JADX reproduction: the Kotlin parser and JVM were not executed. ### Reproduction From the source checkout, save this reduced boundary probe as `/tmp/rea-manifest-prefix.mts` and run `REA_ROOT="$PWD" node_modules/.bin/tsx /tmp/rea-manifest-prefix.mts`. It deliberately simulates the pinned producer using its published expressions; it does not claim to execute that producer. ```ts import { pathToFileURL } from 'node:url'; const { analyzeJadxRequest } = await import(pathToFileURL( `${process.env.REA_ROOT}/src/android/JadxAnalysis.ts`).href); const engine = { name: 'jadx', version: '0.7.1', artifact_sha256: 'a'.repeat(64), source_revision: null, worker_count: 1, heap_limit_mib: null, }; for (const prefix of ['android', 'a']) { const xml = `<manifest xmlns:${prefix}="http://schemas.android.com/apk/res/android" package="org.example.fixture" ${prefix}:versionName="one" ${prefix}:versionCode="7"><uses-sdk ${prefix}:minSdkVersion="23" ${prefix}:targetSdkVersion="35"/><uses-permission ${prefix}:name="org.example.fixture.MARKER"/><application/></manifest>`; const app = { package: /<manifest\b[^>]*\bpackage="([^"]+)"/u.exec(xml)?.[1] ?? '', version_name: /android:versionName="([^"]+)"/u.exec(xml)?.[1] ?? '', version_code: /android:versionCode="([^"]+)"/u.exec(xml)?.[1] ?? '', min_sdk: /android:minSdkVersion="([^"]+)"/u.exec(xml)?.[1] ?? '', target_sdk: /android:targetSdkVersion="([^"]+)"/u.exec(xml)?.[1] ?? '', permissions: Array.from(xml.matchAll(/<uses-permission\b[^>]*android:name="([^"]+)"/gu), m => m[1]), }; const result = await analyzeJadxRequest({ json: async () => app, text: async () => xml, listClasses: async () => { throw new Error('unused'); }, }, { operation: 'inspect_android_package', input: { path: '/fixture.apk' } }, { state: 'LOADED', apk_path: '/fixture.apk', class_count: 0, resource_count: 1, threads: 1, resources: 'full', }, engine); console.log(JSON.stringify({prefix, result})); } ``` The retained rerunnable probe used the same adapter and extracted these expressions directly from the pinned Kotlin source. Each prefix was examined once before writing this report. ### Expected behavior Equivalent namespace bindings should produce equivalent manifest summaries: version name `one`, version code `7`, min SDK `23`, target SDK `35`, and the declared marker permission. XML [expanded names](https://www.w3.org/TR/xml-names/#dt-expname) use namespace URI plus local name; the prefix is a placeholder. This is reachable in the producing decoder by source inspection: JADX 1.5.6 [preserves a declared namespace prefix](https://github.com/skylot/jadx/blob/4c0ac37699aa8c9803f1c73cfaacd9205acb044b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java#L169) and [uses that mapping to print attributes](https://github.com/skylot/jadx/blob/4c0ac37699aa8c9803f1c73cfaacd9205acb044b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java#L338). It generates the conventional `android` prefix only when a mapping is absent. No APK decoder run was performed for this report. ### Impact and scope The structured package summary can lose declared version, SDK and permission facts for this namespace representation. This is static metadata correctness, with no execution or authenticity claim. The boundary probe retains the complete XML, so inspecting that XML recovers the facts. Real APK frequency and end-to-end behavior remain NOT_ENOUGH_INFO: no JDK/JADX engine was available for this pass. ### REA version 6.7.0, source `e2efd10b70a2b5f15a7ac1b5a457a9a1dbcab4d4`. ### Runtime and platform Boundary probe: Node.js v24.22.1, Linux 7.2.8-9-omarchy x86_64. No Java runtime, Android SDK, device or APK execution. ### Target and artifact context Two benign authored XML manifests differing only in namespace prefix, plus simulated upstream summaries. No actual APK or private target data. ### Interface Other ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Selected fields from the observed adapter output: ```text prefix version_name version_code min_sdk target_sdk permissions android one 7 23 35 [org.example.fixture.MARKER] a null null null null [] ``` Both outputs retain their respective full manifest with `status: complete`. - Evidence provenance: source-derived producer behavior; observed simulated-boundary projection. - Local verification: boundary probe executed; original Kotlin/JADX pipeline not executed. - Reproduction completeness: complete adapter-boundary example; real binary-XML APK reproduction missing. - [Pinned producer expressions](https://github.com/1013503897/jadx-headless-mcp/blob/5844800a486d2248fa949b74c9896285f5b54de2/src/main/kotlin/com/atxx/jhmcp/ManifestParsing.kt#L15). - [REA's summary forwarding](https://github.com/morluto/rea/blob/e2efd10b70a2b5f15a7ac1b5a457a9a1dbcab4d4/src/android/JadxAnalysis.ts#L117). - [REA's audited producer pin](https://github.com/morluto/rea/blob/e2efd10b70a2b5f15a7ac1b5a457a9a1dbcab4d4/src/android/JadxRelease.ts#L2). ### Typed outcome or recovery expected Preserve the declared scalar fields and permission names independent of prefix spelling, or explicitly report that the summary cannot be interpreted. Retain the XML evidence. ### Analysis or suspected cause Source-derived: the pinned producer's literal-prefix regexes omit these attributes; REA accepts that summary without namespace-aware interpretation. The decoder source supports prefix preservation, but the complete binary-XML path remains unverified. ### Additional context Open and closed searches for `JADX namespace`, `manifest prefix`, `manifest summary` and `namespace Android` found no matching report; the supplied 1,067 open issue bodies were also searched. No known-good release was established. A proposed next check is to compile an ordinary manifest using the `a` prefix and run the real pinned JAR; that check was not run. ## Triage assessment - Impact level: P2 - Assessment status: provisional - Impact basis: The source and boundary probe support loss of structured manifest facts for equivalent namespace bindings; a real binary-XML/JADX run is missing, so end-to-end reach remains provisional. - Workaround status: available - Workaround basis: The executed boundary probe retains the complete manifest text with every affected value, allowing direct inspection of the same evidence.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4165
No description provided.