Skip to content
AI & Agents
Skill

/happy-app-audit

Audit a local macOS app's telemetry / reporting behavior using static analysis only. Reverse-engineers an .app bundle to identify embedded SDKs (AppLog/TEA, Parfait, TTNet, mars, MMKV, Sentry, Firebase, Bugly, Umeng, etc.), mapped upload endpoints, local on-disk queues, and

From plugin
happy-claude-skills
30313 skills
Install
$ npx -y skills add iamzhihuix/happy-claude-skills --skill happy-app-audit --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/happy-app-audit

Context preview

The summary Claude sees to decide when to auto-load this skill.

Audit a local macOS app's telemetry / reporting behavior using static analysis only. Reverse-engineers an .app bundle to identify embedded SDKs (AppLog/TEA, Parfait, TTNet, mars, MMKV, Sentry, Firebase, Bugly, Umeng, etc.), mapped upload endpoints, local on-disk queues, and

SKILL.md

happy-app-audit.SKILL.md
name: happy-app-audit
description: Audit a local macOS app's telemetry / reporting behavior using static analysis only. Reverse-engineers an .app bundle to identify embedded SDKs (AppLog/TEA, Parfait, TTNet, mars, MMKV, Sentry, Firebase, Bugly, Umeng, etc.), mapped upload endpoints, local on-disk queues, and privacy-relevant fields — without packet capture, network requests, debugger attach, or DRM bypass. Use when user asks to investigate, audit, or reverse-engineer a macOS app for telemetry, reporting, data upload, privacy, or SDK fingerprinting. Targets /Applications, ~/Applications, /Library/Input Methods, /Library/PrivilegedHelperTools, and similar local install paths.
metadata:
  author: iamzhihuix
  version: "0.1.0"

Happy App Audit

Static-only macOS app telemetry auditor. Produces a markdown report describing what an installed `.app` bundle reports, to whom, how often (inferred), and what it leaves on disk.

When to invoke

Invoke when the user says any of: "审计 / 调查 / 看看 / 拆 / 逆向 / 上报 / 埋点 / 隐私 / 抓 SDK" combined with a `.app` path or app name. Also invoke when given paths under `/Applications`, `~/Applications`, `/Library/Input Methods`, or `/Library/PrivilegedHelperTools`.

Do **NOT** invoke for: source-code repos, web sites, mobile (iOS/Android) packages — this skill is macOS-bundle specific.

Hard rules (non-negotiable)

  • **Read only.** No `curl/wget/nc/dig` against discovered endpoints. No `lldb attach`, `dtrace`, `fs_usage`, `tcpdump`, `mitmproxy`, `frida`. No Keychain reads. No DRM bypass. No memory dump.
  • **Allowed commands only.** See `references/safe_commands.md`. If a step seems to need something outside the whitelist, stop and tell the user instead of improvising.
  • **Privacy by default.** In every output file, scrub `device_id`, `uid`, `session_id`, `email`, IDFV, IDFA, JWT, and any 16+ hex blob to `<redacted:N>` (keep length, drop content).
  • **Scope cap.** Refuse a single invocation that targets more than 5 apps. Refuse paths under `/System/`, `/usr/libexec/`, `/private/var/db/com.apple.*`. Those are OS components, not third-party telemetry targets.

Runtime

`{baseDir}` = directory of this SKILL.md.

All scripts are bun + TypeScript. Resolve runtime as: prefer `bun` in PATH, otherwise `npx -y bun`. If neither exists, abort with a one-line install hint.

# Smoke check
bun --version  ||  npx --version  ||  echo "Need bun (recommended) or npx"

Workflow — 6 phases, in order

Each phase has: **Goal → Inputs → Commands → Output → Stop conditions**. Do not skip ahead. Do not interleave.

Phase 0 — Scope confirm

**Goal.** Lock the target list to ≤5 valid `.app` paths.

**Inputs.** Whatever the user said — could be a path, a name, or "the input methods I have installed."

**Commands.**

  • If user gave a path → verify it exists and ends with `.app`
  • If user gave a name → search a fixed list:
  /Applications         (depth 2)
  ~/Applications        (depth 2)
  /Library/Input Methods (depth 1)
  /Library/PrivilegedHelperTools  (depth 1)
  • Reject anything under `/System/`, `/usr/libexec/`, `/private/var/db/com.apple.*`

**Output.** A list `target_apps[]` with absolute paths.

**Stop.** If the list is empty, ask the user once. If >5, ask which to keep.

Phase 1 — Metadata snapshot

**Goal.** Per app, capture the immutable surface: bundle id, version, signing, entitlements, network policy, embedded frameworks.

**Inputs.** `target_apps[]` from Phase 0.

**Commands.** Run `scripts/snapshot_app.ts`:

bun {baseDir}/scripts/snapshot_app.ts <app-path> --out <workdir>/meta.json

The script collects:

  • `plutil -p <app>/Contents/Info.plist`
  • `codesign -dv --entitlements - <app>` (stderr)
  • `find <app>/Contents/Frameworks -maxdepth 3 -name '*.dylib' -o -name '*.framework'`
  • `otool -L <main-binary>`
  • `file <main-binary>` for arch
  • Sizes via `du -sh`

**Output.** `<workdir>/meta.json` with: `bundle_id`, `version`, `sandboxed`, `arbitrary_loads`, `ats_exceptions[]`, `entitlements_summary[]`, `frameworks[]` (each: name, path, size_bytes, archs).

**Stop.** If `bundle_id` cannot be read → abort, app is malformed.

Phase 2 — Strings preprocessing

**Goal.** Turn raw `strings` of every embedded binary into bucketed markdown that fits in context.

**Inputs.** `meta.json::frameworks[]`.

**Commands.**

bun {baseDir}/scripts/classify_strings.ts <workdir>/meta.json --out <workdir>/strings/

For each binary, the script runs `strings -a -n 6` and sorts each line into one of:

  • `urls` — anything matching `https?://`
  • `domains` — bare hostnames
  • `paths` — `/Library/...`, `~/Library/...`, container-relative paths
  • `sql` — `CREATE TABLE`, `INSERT INTO`, `SELECT ... FROM`
  • `events` — looks like an event name (`/^[a-z][a-z0-9_]{8,80}$/` with at least one underscore)
  • `keys` — base64 / hex blobs ≥ 24 chars (kept count + first 12 chars only, never full)
  • `noise` — discarded

**Output.** `<workdir>/strings/<binary-name>.{urls,domains,paths,sql,events}.md` (the `keys` bucket holds only counts + redacted previews).

**Stop.** If a binary is >200 MB → skip it and emit a warning line, do not OOM.

Phase 3 — SDK fingerprint matching

**Goal.** Identify which third-party SDKs are present and how confident.

**Inputs.** `<workdir>/strings/`, plus `references/sdk_fingerprints.md`.

**Commands.**

bun {baseDir}/scripts/match_fingerprints.ts <workdir>/strings/ \
  --fingerprints {baseDir}/references/sdk_fingerprints.md \
  --out <workdir>/matched.md

The script applies each fingerprint's `tell-tale strings` regex set to the bucketed strings. A fingerprint counts as **confirmed** when its `min_hits` threshold is met (defined per fingerprint).

**Output.** `<workdir>/matched.md` with one row per SDK: name, vendor, hits, evidence file lines, status (confirmed / partial / absent).

**Stop.** If zero fingerprints confirmed AND the app embeds no third-party `.framework` → write a one-line "no telemetry detected"

Read more
Ships withhappy-claude-skills

A collection of practical skill plugins for AI coding agents. Works with Claude Code, Codex, Factory Droid, OpenClaw, Cursor, and 40+ agents.

Get the whole plugin
Stats
304
Stars
29
Forks
Maintained
Maintenance
TypeScript
Language
MIT
License
4mo ago
Last commit
7mo ago
Created

Repo: iamzhihuix/happy-claude-skills

Other skills on happy-claude-skills.