Skip to content

Phase 11: result normalization (occurrences + applies_to + dedup) - #29

Merged
sp3arm4n merged 6 commits into
mainfrom
sp3arm4n
May 12, 2026
Merged

Phase 11: result normalization (occurrences + applies_to + dedup)#29
sp3arm4n merged 6 commits into
mainfrom
sp3arm4n

Conversation

@sp3arm4n

Copy link
Copy Markdown
Owner

Summary

KakaoTalk audit showed three duplication patterns:

  • 190 PoCs for 51 manifest findings (3.7× blow-up)
  • 49 of 103 code findings shared (rule, class) — same problem repeated
  • java/smali overlap dropped smali evidence silently

Phase 11 normalises the data layer + HTML so the report shows what
the analyzer actually found, compactly.

  • P11-1 cbc4c94 CodeFinding.occurrences — same (rule, class, severity)
    collapses to representative + list of additional line refs
  • P11-2 cb38329 MANIFEST-004 single-PoC-per-component — N actions
    become one .sh trying each action sequentially (was: N separate .sh)
  • P11-3 214a0d4 PoC template dedup — same (rule, kind, severity,
    normalized template) merges; applies_to carries other components
  • P11-4 d4e3cf2 HTML grouping UI — "×N건" badge + collapsible
    occurrence list + "+N 적용" chip + applies_to inline list
  • P11-5 b1aecc9 java/smali tier overlap fold — smali primary +
    occurrences fold into java rep's occurrences as additional evidence
    (was: dropped silently)

KakaoTalk before/after:

Metric Before (Phase 10) After Phase 11 Change
Manifest PoCs 190 17 −91%
Java code findings 103 55 −47%
Smali code findings 306 151 −51%
Merged code cards 234 200 −15%
Occurrence evidence rolled in 0 211 (no evidence dropped)

Test plan

  • 849 → 864 unit tests passing (+15: 8 P11-1, 1 P11-2, 9 P11-3,
    4 P11-4, 3 P11-5)
  • KakaoTalk regression validated against existing apktool/jadx
    output — numbers above are real (not projected)
  • JSON round-trip for new fields (CodeFinding.occurrences,
    PoCArtifact.applies_to) — both default to empty list and omit
    from to_dict when unused, so older payloads load forward-compat
  • HTML test suite covers occurrence badge / details / applies_to chip
  • (manual) re-run apk-batch-audit skill — confirm card counts
    drop without losing findings (operator manual verification)

Codex review handoff

outputs/intent.md — per-unit intent / risk / verification checklist.

🤖 Generated with Claude Code

sp3arm4n and others added 6 commits May 13, 2026 02:18
KakaoTalk audit produced 103 code findings but only 54 unique
(rule, class) keys — 49 of 103 were the same rule firing repeatedly
inside the same class (e.g. com.caverock.androidsvg.i fired CODE-001
12 times). Operators scrolled past identical cards.

This commit collapses findings sharing (rule_id, class_fqn, severity)
into one representative + a list of additional occurrences:

  CodeFinding gains:
    occurrences: list[CodeOccurrence] = []
    occurrence_count property (1 + len(occurrences))

  CodeOccurrence (new dataclass) carries:
    line_no, line_text, file (only when different from primary),
    evidence_tier (inherits the parent finding's tier by default)

  dedup_findings_by_class(findings) helper applies the merge — used
  by audit_code() and audit_smali() at their respective return paths.

Severity is part of the key so CODE-002's medium
setJavaScriptEnabled(true) and high addJavascriptInterface stay
as two findings (operators triaging by severity would lose the
high signal otherwise).

JSON round-trip: occurrences serialize only when non-empty; default
empty list keeps older payloads compact and forward-compatible.

KakaoTalk effect (back-of-envelope from existing partial scan):
  103 findings → 54 representatives (47% compression)
  Same evidence retained as occurrences; nothing dropped.

Tests +14:
  - dedup empty / distinct rules / distinct classes / same class collapse
  - severity-aware key prevents merging different severities
  - exact-line duplicate folded down to representative only
  - class_fqn=="" falls back to file as grouping anchor
  - evidence_tier preserved in CodeOccurrence
  - CodeFinding to/from_dict round-trips occurrences
  - audit_code() end-to-end dedup via real source files

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
KakaoTalk's RecentExcludeIntentFilterActivity carries 43 intent-filter
actions and the audit emitted 43 separate adb PoCArtifacts, each
running one ``am start -a <action>`` command. Operators saw the same
template repeated 43 times, with only the action string changing.

This commit consolidates per-component: one PoCArtifact per exported
component whose commands list runs every action sequentially. The
artifact title is "<type> '<class>' 호출 — N actions" when there are
multiple actions, and the single-action case keeps the old short title.

Effect on KakaoTalk regression (back-of-envelope):
  - 190 PoCs → ~50 PoCs (single-PoC-per-component + Frida observer +
    deeplinks unchanged)
  - The most repetitive case (43 actions in one component) becomes
    one 45-line .sh

The Frida observer artifact and deeplink PoCs are unchanged — those
already operate at component scope. Only the per-action adb fanout
collapses.

Tests +1, modified existing test to reflect single-PoC semantics:
  - test_actions_grouped_into_single_artifact_per_component
  - test_single_action_no_action_count_suffix (clean title case)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
KakaoTalk emitted 190 PoCArtifacts where many shared the same shell /
adb template — only the component class FQN or deeplink URI differed.
Operators got identical .sh scripts with just one varying token,
making the bundle exhausting to scan.

This commit adds template-level dedup on top of the per-component
collapse from Phase 11-2:

  PoCArtifact gains:
    applies_to: list[str]    # other targets the same template covers

  dedup_pocs_by_template(artifacts) helper folds artifacts sharing
  (rule_id, kind, severity, command-template) into one representative
  + applies_to list of additional targets. generate_pocs() runs the
  dedup automatically before returning.

Template signature normalizes:
  - com.* class FQNs and dotted hostnames → <T>
  - kakao{type}:// and http(s):// URIs → <T>
  - title strings get the same substitution
So "외부 노출 액티비티 'com.demo.A' 호출" + commands "am start -n A"
matches the same shape as ".B" / "am start -n B".

Severity and kind are part of the key — high vs medium templates stay
separate (operators triaging by severity must not lose the high
signal). Different transports (adb / frida) also remain separate.

Effect on KakaoTalk regression (with P11-2 already applied):
  ~50 PoCs → ~25-30 PoCs after template fold; each surviving PoC now
  carries applies_to with the merged component FQNs so the operator
  sees "이 .sh는 다음 N개 컴포넌트에 적용 가능" at-a-glance.

Tests +9:
  - empty input / unique passthrough / same-shape different-component
  - 3 → 1 with applies_to listing both extras
  - severity and kind respected (no cross-merge)
  - deeplink URI host normalization
  - applies_to JSON round-trip + omit when empty

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders the Phase 11-1 / 11-3 dedup outputs so the HTML report shows
the compression the data layer already achieves:

CodeFinding cards:
  - "×N건" sev-chip badge in the card header when occurrence_count > 1
  - "tier: smali" badge when evidence_tier != "java" (java tier omits)
  - Collapsible <details> with "동일 클래스 내 추가 단서 N건 펼치기"
    listing every occurrence (line_no, line_text, file when different,
    evidence_tier label when it diverges from the parent finding)
  - Badge / details omitted entirely when count == 1 and occurrences
    is empty — single findings render identically to pre-Phase-11

PoC <details> entries:
  - "+N 적용" chip in summary when applies_to has entries
  - Inline <ul> under "다음 컴포넌트에도 동일 템플릿 적용 가능"
    so the operator can copy alternative targets without leaving the
    card
  - Chip / list both omitted when applies_to is empty

Pre-existing severity / MASVS / partial banners are untouched; the
new badges sit alongside them in the card header.

Tests +4:
  - code finding occurrence badge + collapsible details + smali label
  - no badge when single occurrence
  - tier: smali label render for smali-tier findings
  - PoC applies_to chip + body list render via real builder output

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
merge_code_reports previously dropped the smali finding entirely when
the .java tier had already reported the same (rule, class). That was
correct for the *card count* but wasted evidence: smali often catches
extra lines that jadx couldn't decompile inside the same class.

This commit folds the smali side into the java representative's
occurrences instead of discarding it:

  - Merge key tightened to (rule_id, class_or_file, severity) so
    different severities of the same rule (CODE-002 medium vs high)
    stay as separate cards — matches the dedup_findings_by_class key
  - On overlap, smali's primary (line_no, line_text, file) folds in as
    a CodeOccurrence with evidence_tier="smali"
  - smali's own occurrences (from smali-tier dedup) also fold in, each
    labelled "smali"
  - File path in the occurrence is omitted when it matches the java
    rep's file (avoids redundant "x.java" everywhere)

Effect on KakaoTalk-class APKs: previously when both tiers hit the
same class, the smali findings disappeared from the report; now they
appear as additional evidence on the java card so operators see the
full picture without inflating the card count.

Tests +2 (1 existing test rewritten):
  - existing "java wins on overlap" updated to assert the smali fold
  - smali's own occurrences (already-grouped smali bundle) also fold
  - different severity on same class keeps two separate cards

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Lead bullets: explicit "PoC 자동 생성 + dedup" with the KakaoTalk
  190→17 (-91%) measurement, "결과 정규화" callout for occurrence
  grouping. HTML bullet mentions the new occurrence expand + chips.
- Project Layout test count bumped 834 → 864.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sp3arm4n
sp3arm4n merged commit e2a50e5 into main May 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant