← all branches

spike/cfe-app

needs attention
0c7f4d4 · incrementalpre-PRreviewed 2026-07-06 16:44 UTC12H · 11M · 12L
The branch
Purpose
Recover the RPU→titleholder name lookup API endpoint from the CFE Contigo mobile app (mx.com.cfe.cfecontigo 4.6.0), which CFE deleted from its public web scraper surface in 2026. The mobile backend still resolves titular from RPU alone via ServiceInfoResponse. Goal: find host+path+auth without a rooted device (static OSINT + deobfuscation), then probe server-side.
Goal
Staged capture toolkit for the Apple Silicon Mac handoff: arm64 emulator + Frida OkHttp hook to intercept the login+service-info requests pre-TLS, confirming whether the read endpoint requires device attestation (feasibility pivot).
Sub-goals
  • SG-1 ✅ — Static analysis of CFE Contigo 4.6.0 APK (OkHttp/Retrofit, DexGuard string-encryption, DTOs confirm server-resolved titular)
  • SG-2 [~] BLOCKED — MITM capture harness built; blocked by x86 emulator SIGSEGV, iOS force-close, non-root Android unrepackageable
  • SG-4 ✅ — Feasibility verdict HTML: DON'T ADOPT for headless add-service (attestation blocks replayability)
  • SG-5 [ ] — Stretch PoC (depends on SG-3)
  • SG-6 [~] PARTIAL — OSINT found appcfecontigo.cfe.mx (live, Imperva-fronted); DexGuard static decryption ruled out (reflection tier); x86_64 emulator ruled out; arm64 + Frida staged; Mac handoff dossier written
The changes (whole branch)
What
This incremental diff adds all 11 research files since the initial branch provision: SG-1 decompile notes, SG-2 mitmproxy addon + Frida scripts + emulator setup + runbook, SG-4 findings HTML, and the SG-6 OSINT notes + Apple Silicon Mac handoff dossier + Frida OkHttp hook. The branch scope and intent log were also updated to reflect the SG-4→SG-6 pivot.
Why
CFE deleted the public IncrementoDeCarga resolver (RPU→name) in 2026. The scraper's registerRpu() now requires the titleholder name as an out-of-band input. The mobile app proves the server still resolves it — recovering that endpoint is the forwward path to restoring automated RPU registration without user-supplied names.
Areas
.branch/+13065docs/spikes/cfe-mobile-app/+1320scripts/cfe/mobile/+6010
Blast
11 files, +863/-65 lines across 3 areas. Pure research spike — no production code, no domain entities, no handlers, no schema changes. All files are under scripts/, docs/spikes/, and .branch/.
research-spike security-research no-production-code handoff-to-user
CI· No CI configured for spike branchCodeRabbit· No .coderabbit.yaml in repotypecheck· No TypeScript files in this difftests· Spike branch — no test suite

Findings · 35

correctness16

high

bodyToStr() drains one-shot RequestBody — breaks POST login/add-service

scripts/cfe/mobile/frida-okhttp.js:22

b.writeTo(buf) on a one-shot RequestBody drains the okio.Source. Both newCall and proceed hooks call logReq, so every POST body is consumed twice — the live app's login POST lands empty → 400/401. Fix: use b.peek().readUtf8() instead.

high

getAcceptedIssuers returns JS [] not Java X509Certificate[0] — ClassCastException in Conscrypt

scripts/cfe/mobile/frida-unpin.js:45

Conscrypt casts the return value to X509Certificate[] — type mismatch throws ClassCastException inside SSL handshake, causing TLS to fail silently. Fix: return Java.use('[Ljavax.net.ssl.X509Certificate;').$new(0).

high

wait_online/wait_boot loops never detect emulator process death — hang for full timeout

scripts/cfe/mobile/setup-emulator.sh:32

If the emulator dies (GPU crash, AVD error), loops run for 120–150 s before failing with no indication of the cause. Fix: save emulator PID and check kill -0 $EMU_PID inside the loop.

high

mapfile -t requires Bash 4.x; macOS ships Bash 3.2 — APKS array stays empty

scripts/cfe/mobile/setup-emulator.sh:65

Script exits '!! no .apk files in $APK_DIR' even when APKs exist. Primary target is macOS (Apple Silicon). Fix: APKS=( "$APK_DIR"/*.apk ) (POSIX-compatible).

high

frida-server download URL may include build suffix from 'frida --version' → 404

scripts/cfe/mobile/mac-capture-dossier.md:82

pip-installed frida returns '16.2.1 (build …)'; GitHub release tag is '16.2.1'. Fix: FV=$(frida --version | awk '{print $1}').

high

XAPK glob '*.apk' misses APKs stored in APKs/ subdirectory — zero APKs installed

scripts/cfe/mobile/mac-capture-dossier.md:73

APKPure XAPKs commonly store splits under APKs/. Fix: unzip -d cfe/ then find cfe -name '*.apk' for install-multiple.

medium

Double-logging: newCall + every RealInterceptorChain.proceed prints the same request 4-5 times

scripts/cfe/mobile/frida-okhttp.js

A single request produces 1 newCall + 4-5 proceed prints, making it hard to identify the actual outgoing network call.

medium

TrustManagerImpl.checkTrustedRecursive 6-arg overload may not match Android 34 — false-positive 'hooked' log

scripts/cfe/mobile/frida-unpin.js:23

Android 34 changed this method signature. If overload mismatches, Frida silently skips it but still logs 'hooked'.

medium

_is_noise() endswith(s) without dot prefix — could suppress CFE traffic matching a noise suffix

scripts/cfe/mobile/mitm-cfe.py:47

host.endswith(s) (no dot prefix) is structurally overly broad. Remove the bare endswith(s) clause — redundant with endswith('.' + s).

medium

Fixed sleep 4 after adb root instead of polling — may leave adbd offline

scripts/cfe/mobile/setup-emulator.sh:54

On a slow host 4 s is not enough for adbd restart. Fix: adb root && wait_online 90.

medium

tmpfs mount blocked by SELinux enforcing — CA install silently fails, 'installed CA' false positive

scripts/cfe/mobile/setup-emulator.sh:58

ls verification only checks /data/local/tmp/mc/ (pre-mount path). Fix: setenforce 0 before mount; split shell chain to check each exit code.

medium

adb shell 'fs &' — SIGHUP kills frida-server when adb session ends

scripts/cfe/mobile/mac-capture-dossier.md:86

Fix: nohup /data/local/tmp/fs > /dev/null 2>&1 & or keep a foreground adb shell terminal.

low

RealInterceptorChain hook failure silently swallowed — operator not told responses are not captured

scripts/cfe/mobile/frida-okhttp.js:57

catch(e){} with no log. Add TAG+' RealInterceptorChain hook skipped: '+e so operator knows they have request-only data.

low

HostnameVerifier hook targets static default — does not affect OkHttp3 per-client verifier

scripts/cfe/mobile/frida-unpin.js:71

Comment 'HostnameVerifier — accept all' overstates effect. OkHttp3 stores verifier on builder instance, not static default.

low

response-only hook misses TLS-layer rejections — attestation block would be invisible

scripts/cfe/mobile/mitm-cfe.py

If the service-info call is rejected at TLS layer, no HTTP response fires and the flow is silently dropped. Runbook should note this gap.

low

Missing fh.flush() — partial JSONL record on crash

scripts/cfe/mobile/mitm-cfe.py

Buffered I/O without flush; on CPython the write may not reach disk before a crash. Add fh.flush() after fh.write().

security4

high

cfe-capture.jsonl NOT gitignored — contradicts runbook; risks committing live CFE credentials and PII

scripts/cfe/mobile/mitm-cfe.py

capture-runbook.md says 'gitignored by default' — false. Neither root .gitignore nor local covers cfe-capture.jsonl. The file contains Bearer tokens, login credentials, and titular names (third-party PII). Fix: add scripts/cfe/mobile/cfe-capture*.jsonl to .gitignore immediately.

medium

frida-okhttp.js logs full Authorization headers and request body to stdout with no masking

scripts/cfe/mobile/frida-okhttp.js

Dossier asks researcher to 'paste [okhttp] output' to Claude Code with advisory-only scrubbing. One paste-without-scrubbing publishes CFE credentials and titular names. Recommended: mask headers matching 'authorization'/'x-auth'/'cookie' after first 12 chars.

medium

APK from APKPure third-party mirror with no signature/integrity check

scripts/cfe/mobile/mac-capture-dossier.md

APKPure has historically served tampered versions. Android verifies APK signatures on install but a validly-signed tampered APK passes. Add apksigner verify --print-certs step with expected SHA-256 fingerprint.

low

tmpfs CA ephemeral (correct) but snapshot interaction undocumented

Restoring an emulator snapshot after CA install drops the tmpfs CA. Add a comment: 'Re-run this step after restoring a snapshot.'

conventions4

low

SG-6 marked [ ] despite active in-progress work across 4 commits

.branch/scope.md:104

Should be [~] (PARTIAL) with a parenthetical summary to match the intent log.

low

Success Criteria not ticked for clearly completed SGs (SG-1, SG-4)

.branch/scope.md:27

All 6 criteria remain [ ] despite SG-1 (app identification) and SG-4 (HTML verdict) being complete.

low

Framework Learnings section is a placeholder — should be populated before SG-N

.branch/scope.md:117

Three SGs have concrete learnings (DexGuard field names survive; x86_64 can't run ARM app; attestation vs TLS pinning are orthogonal) that should flow here before SG-N.

low

Commit f834d195 omits SG prefix — breaks scannable-by-subgoal convention

All other spike commits follow 'docs(cfe): SG-N — …'. This one has 'docs(cfe): elevate the RPU->name read…' without SG tag.

tests3

low

setup-emulator.sh does not verify app actually installed after adb install-multiple

scripts/cfe/mobile/setup-emulator.sh:65

Add adb shell pm list packages | grep cfecontigo after install-multiple. The mac-capture-dossier includes this check; the script should too.

low

Proxy setting written but never read back to confirm it applied

scripts/cfe/mobile/setup-emulator.sh:62

Add adb shell settings get global http_proxy immediately after put to confirm proxy is active.

low

mac-capture-dossier.md boot-completion check has no visible success signal

scripts/cfe/mobile/mac-capture-dossier.md

The until-getprop loop exits silently. Clarify expected output ('1' → proceed) so the operator knows the step succeeded.

improvement8

high

isNoise() checks full URL string — could suppress appcfecontigo.cfe.mx if query param contains noise domain

scripts/cfe/mobile/frida-okhttp.js:19

Extract host before NOISE check; add explicit cfe.mx allow-list: if (host.endsWith('cfe.mx')) return false — prevents ever losing the target host.

high

Authenticator callbacks not hooked — token-refresh leg invisible

scripts/cfe/mobile/frida-okhttp.js

OkHttp fires Authenticator.authenticate on 401/407. Token-refresh login and retried request with fresh token are invisible. Hook okhttp3.Authenticator via Java.use + implementation to log trigger URL and returned Request.

high

setup-emulator.sh hardcodes x86_64 — contradicts dossier, will SIGSEGV app on Apple Silicon

scripts/cfe/mobile/setup-emulator.sh:16

Auto-detect HOST_ARCH=$(uname -m) and branch: arm64 → android-34/arm64-v8a/pixel_6; x86_64 → warn or abort with redirect to dossier.

high

No anti-root/emulator-detection Frida script staged — most likely blocking failure on handoff

scripts/cfe/mobile/mac-capture-dossier.md

iOS app force-closed on MITM; Android emulator/root detection is the same class of defense. Stage frida-antid.js covering RootBeer no-op, Build.TAGS/FINGERPRINT spoofing, File.exists('/system/bin/su') → false. Pre-staging removes a full roundtrip delay.

high

apk-mitm with pinned apktool 2.9.3 is an untried fast path — could eliminate Frida entirely

scripts/cfe/mobile/read-endpoint-notes.md

The failure was toolchain version mismatch (apktool≥2.10), not a CFE defense. Try: apk-mitm --apktool /tmp/apktool293.jar cfe.apk. If it succeeds, mitmproxy captures everything with no Frida. 20-min experiment with high upside.

medium

TrustKit (com.datatheorem.android.trustkit) not covered in frida-unpin.js

scripts/cfe/mobile/frida-unpin.js

TrustKit overrides pinning at the OkHttp interceptor layer, not via TrustManagerImpl or CertificatePinner. Common alongside DexGuard. Add best-effort hook on com.datatheorem.android.trustkit.pinning.PinningTrustManager.checkServerTrusted wrapped in try/catch.

medium

HOT list has duplicate 'cuenta' + response body not inspected for keywords

scripts/cfe/mobile/mitm-cfe.py:41

Remove duplicate. Extend hay to include _body(resp) — a GET /servicios/{rpu} carries 'titular' only in the response; without this, the lookup goes untagged.

medium

Waydroid on the dev machine not attempted — viable x86_64 path removing Mac dependency

scripts/cfe/mobile/read-endpoint-notes.md

Waydroid runs ARM Android container on x86_64 Linux, is rootable via Magisk. A 30-min experiment could eliminate the Mac handoff entirely. Add to next-options with install steps.

History · 2 commits

  1. 0c7f4d4needs attentionincremental12H · 11M · 12L2026-07-06 16:44current
  2. e4824e9needs attentionfull9H · 11M · 8L2026-07-05 06:06