--- name: detect-data-leaks description: Detect new PII leaks introduced by the current branch. Use when asked to check for potential data leaks for the current changes. --- # Scope — what is PII, what is NOT We only consider PII that is sent to third-party services. Any call to our own backend with PII is not considered a data leak. Every third-party service should be considered, but each has a different risk level. Logging services are the highest risk. Some information is only PII in context — for example, public addresses are not PII by themselves, but on a logging service such as Datadog, an address can be linked to a location and device, allowing identification of the person behind it. Crash reports need to be studied alongside logs — they are a common source of data leaks. Any service that queries the blockchain for an address is **not** a concern — the query is mandatory for the system to function and the data is not linked to any other identifiable information. This applies to all coin modules. Examples: - Kaspa → `api.kaspa.org` - EVM (Ethereum, BSC, Polygon…) → Etherscan-family - Tron → TronGrid (`api.trongrid.io`) # Known third-party sinks in this repo Prioritize these, but do not exclude others: - Datadog - Sentry - Mixpanel # High-risk variables Treat any of these as high-risk when found in added lines: `location.pathname`, `window.location.hash`, `address`, `walletAccountId`, `txId`, `publicKey`, `signature`, `rawData`, `payinAddress`, `fromAccountAddress`, `toAccountAddress`, `binaryPayload` # Process 1. Run `git diff develop...HEAD`. This is the primary source — start here, not from grep. 2. In added lines, identify: - Assignments of high-risk variables (see above) - New calls to third-party sinks or wrappers: `track()`, `trackPage()`, `logger.*()`, `captureException()` 3. In removed lines, identify: - Removed guards: `confidentialityFilter`, scrubbing calls, PII-stripping wrappers — flag each removal as a potential leak enabler. 4. For each high-risk variable in added lines, trace its lineage: - Check if it flows into a sink call within the diff - If it may pass through intermediate calls, read the affected file to follow the chain 5. For each new sink call in the diff: - Read surrounding context in the file - Follow the call chain to determine what gets serialized - If the call is a wrapper (e.g. `track()`), read its implementation — do not assume from the name 6. Use the grep commands below only to trace a pattern already found in the diff. Never run them independently to source findings. 7. Score each finding 1–10. Report only those scoring 7 or higher with a concrete fix. # Grep helpers (investigation only) **`location.pathname` flowing into `track()`** — pathname often assigned before the call: ```bash find apps \( -name "*.ts" -o -name "*.tsx" \) | grep -vE "\.test\.|/__tests__/|/tests/" | \ xargs perl -0777 -ne 'BEGIN { exit unless @ARGV } print "$ARGV\n" if /track(?:Page)?\([\s\S]{0,500}?location\.pathname/' ``` **`window.location.hash` in analytics:** ```bash grep -rn "window\.location\.hash" apps/ --include="*.ts" --include="*.tsx" ``` **Address interpolated into `new Error(...)` in coin modules:** ```bash find libs \( -name "*.ts" -o -name "*.tsx" \) | grep -vE "live-e2e-shared|coin-tester-modules|__tests__|tests|\.test\." | \ xargs perl -0777 -ne 'BEGIN { exit unless @ARGV } print "$ARGV\n" if /new Error\(`[\s\S]{0,300}?\$\{[^}]*(address|sender|hash|walletAccountId|txId|publicKey)[^}]*\}/i' ``` **Signed tx payload on broadcast failure:** ```bash grep -rn -E "broadcast_failure|broadcastLogger" apps/ --include="*.ts" | grep -v "\.test\." ``` **Full transaction object spread into analytics:** ```bash grep -rn -E "value:[[:space:]]*(params|transaction)\b" apps/ --include="*.ts" --include="*.tsx" \ | grep -v "\.test\." \ | grep -vE "value:[[:space:]]*(params|transaction)\." ``` **Signed payload fields in `track()`:** ```bash grep -rn -E "binaryPayload|payinAddress|fromAccountAddress|toAccountAddress" libs/ apps/ --include="*.ts" --include="*.tsx" \ | grep -vE "\.test\.|/__tests__/|/tests/" ``` **Props filter registration (the shared pipeline applies it to both `track()` and `trackPage()`):** ```bash grep -rn "setPropsFilter(" apps/ --include="*.ts" --include="*.tsx" | grep -v test ``` Desktop registers `confidentialityFilter`; check whether any other app that sends analytics needs a filter. # Output format - Score mapping: 9-10 → 🔴 Critical, 7–8 → 🟡 Suggestion. Scores below 7 are not reported. - If no findings reach score 7, produce no output. ``` 🔴 Critical (10/10) — apps/.../useActivityIndicator.ts:39 track("SyncErrorList", { page: location.pathname, ... }); Fix: remove `page` from the payload or replace with a static route label stripped of account IDs. 🟡 Suggestion (8/10) — apps/.../someFile.ts:12 track("Event", { hash: window.location.hash }); Fix: pass only the route segment before the `#`, not the full hash. ``` # References `.agents/skills/client-ids/SKILL.md`