name: pharn-logging-masking-audit skill: "pharn-logging-masking-audit" version: "0.33.2" description: "Deep PII-masking audit on the non-analytics telemetry surfaces: error tracking (Sentry et al.), application logging (Pino/Winston/Bunyan/console), and request-response logging middleware. Three parallel sonnet agents, one per surface. Standalone — not wired into /pharn-ship." kind: pharn-owned module: pharn-audits audit_class: privacy-focused focus: "Error-tracking + application-logging + request-logging PII masking" model_tier: sonnet recommended_effort: medium priority: pharn-owned depends_on: [] soft_depends_on:
- "privacy-shield"
pipeline_wired: false
v1_scope:
in:
- "Sentry (init config, setUser, captureException, breadcrumbs)"
- "Pino (redact config, log call sites, serializers)"
- "Winston (format config, log call sites)"
- "Bunyan (serializers, log call sites)"
- "console (raw console calls)"
- "Request-response logging middleware (Next.js, morgan, fastify, custom)"
- "Generic error tracking (Bugsnag, Rollbar, Honeybadger — light coverage)" out:
- "Log aggregation tooling configs (CloudWatch, DataDog, Splunk, Loki)"
- "Log retention / archival policies"
- "Log transport TLS configuration"
- "Custom logging libraries outside the listed primaries"
- "Runtime config mutations (flagged for manual review)" reads:
- ".claude/CONSTITUTION.md"
- "features/*/PLAN.md"
- "pharn.config.json"
- "**/sentry*.{ts,tsx,js,jsx}"
- "**/instrumentation*.{ts,js}"
- "**/logger*.{ts,js}"
- "**/middleware*.{ts,js}"
- "**/*.{ts,tsx,js,jsx}" writes:
- ".claude/audits/logging-masking-
.md" modes: - default flags:
- --scope <error-tracking|logging|request|all>
- --features
- --quick
- --export <md|html> audit_severity:
- "🔴 LEAK — PII actually leaks to logs/error tracking"
- "🟠 AT RISK — potential leak / config gaps / dynamic content"
- "🟢 BEST PRACTICE — defense-in-depth" pharn_version: "0.67.1" seal: "PHARN ✓ reviewed"
/pharn-logging-masking-audit
A focused, deep audit on PII masking across the non-analytics telemetry surfaces — error tracking (Sentry and similar), application logging (Pino / Winston / Bunyan / raw console), and request-response logging middleware. Three parallel sonnet agents cover the three surfaces: error-tracking interprets error-tracker init config and usage call sites; structured-logging scans logger configuration and log call sites; request-response-logging scans middleware that captures HTTP request/response data. Findings are emitted in a standing audit-finding schema and consolidated into a structured report. Agents run in parallel; the audit is resilient — an individual agent error or an inapplicable surface is recorded in the report and never halts the other agents.
This is the second Tier 2 audit skill in pharn-audits, and with /pharn-posthog-masking-audit it completes Tier 2 (2 of 2). Tier 1 (privacy, security, accessibility, drift-check) audits against external standards or internal consistency; Tier 2 audits go deep on a specific telemetry surface. Where the PostHog audit owns the analytics surface, this audit owns error tracking and logging.
Relationship to the other telemetry-masking tooling
Three siblings divide telemetry masking; none replaces the others, and they are expected to overlap on obvious cases.
/pharn-privacy-audit's telemetry auditor |
/pharn-posthog-masking-audit |
/pharn-logging-masking-audit (this audit) |
|
|---|---|---|---|
| Scope | Broad sweep — analytics + error tracking + logs | Analytics (PostHog) — deep | Error tracking + application logging + request logging — deep |
| Surface | One cross-cutting auditor | config + events + dom | error-tracking + structured-logging + request-response-logging |
| When | Quarterly comprehensive privacy review | Before deploying session replay / new events | Before deploying Sentry, when adding logging, after a near-miss |
| Refs | GDPR articles (telemetry hygiene framing) | posthog_rule_ref + gdpr_ref |
tool_rule_ref + gdpr_ref |
| Output | Findings in the privacy-audit report | PostHog masking report | Logging masking report in .claude/audits/ |
The three deep audits divide telemetry along tool lines; the privacy-audit telemetry auditor catches what they all share. Both deep audits should agree with the broad telemetry auditor on obvious cases; they go deeper where the broad audit doesn't have room. Run this audit when you need depth on Sentry-class error tracking and on Pino/Winston/Bunyan/console + request-logging middleware.
Analytics masking (PostHog
captureproperties, session replay) is out of scope here — that surface belongs to/pharn-posthog-masking-auditand the broadtelemetryauditor. This audit does not cover analytics.
The three PII-leak surfaces this audit covers
- Error-tracking surface. Sentry's server-side SDK captures IPs, user context, headers, cookies, query strings, and request bodies by default when
sendDefaultPii: true. CustomSentry.setUser()calls often include emails. Stack traces sometimes embed parameter values containing PII. Breadcrumbs accumulate context that may include PII. - Structured-logging surface. Pino, Winston, and Bunyan all support redaction config, but it must be explicitly set up. Log call sites often pass entire user/request objects (
logger.info({ user })); default-level logging in production may include PII atinfo/debuglevels that were only meant for development. - Request-response logging surface. Middleware that logs HTTP requests/responses can leak the most data: POST/PUT bodies (form submissions, JSON payloads with PII),
Authorizationheaders, session cookies, and query strings.
Sentry IP capture: the headline concern
Sentry's server-side SDK captures req.ip by default when sendDefaultPii: true — and sendDefaultPii: true is the master switch that also enables capture of user context, headers, cookies, and query strings. For a project subject to GDPR, this is a default-on PII collection that should be explicitly opted out of (or scoped via a beforeSend hook) unless IP addresses are operationally required (fraud detection, geofencing). The error-tracking agent flags sendDefaultPii: true as 🔴 LEAK when the project handles declared PII — the same headline-finding pattern other masking audits use for their most consequential default-on setting.
Severity semantics
Audit 🔴🟠🟢 here means LEAK / AT RISK / BEST PRACTICE. This is distinct from review severity (🔴 blocking / 🟠 should-fix / 🟢 nice-to-have) and from the other audits' severity glossaries. Same glyphs, different semantics — severity meaning is context-bound.
| Glyph | Logging-masking audit meaning | Review meaning |
|---|---|---|
| 🔴 | LEAK — PII actually leaks to error tracking or logs (e.g. sendDefaultPii: true, logger.info logs a PII object, middleware logs the request body) |
Blocking — stops pipeline |
| 🟠 | AT RISK — potential leak: masking-config gaps, dynamic log content that may contain PII, a beforeSend that may not handle all cases |
Should-fix — strong recommendation |
| 🟢 | BEST PRACTICE — defense-in-depth: more granular redaction, sampled error tracking, log-level appropriateness | Nice-to-have — optional improvement |
A finding is only 🔴 LEAK when PII demonstrably reaches a telemetry destination. A static-analysis suspicion (dynamic content, complex beforeSend, runtime mutation) is 🟠 AT RISK with manual_review_required: true — never 🔴.
When to use this skill
- "audit Sentry masking", "check logging PII", "IP masking review", "run the logging masking audit"
/pharn-logging-masking-audit- Before deploying Sentry (especially the server-side SDK)
- When adding structured logging (Pino / Winston / Bunyan)
- When introducing request-logging middleware
- Quarterly, alongside the broader
/pharn-privacy-audit - After a near-miss leak via logs or error tracking (post-mortem)
The audit pipeline
Agent assumptions (applies to every sub-agent spawned by this audit):
- All tools are functional and will work without error. Do not test tools or make exploratory calls. Make sure this is clear to every sub-agent that is launched.
- Only call a tool if it is required to complete the task. Every tool call should have a clear purpose.
1. DISCOVER — gather inputs: constitution P1 (Privacy by Default), all features/*/PLAN.md
## Compliance PII inventories, pharn.config.json, Sentry init (sentry*.* and
instrumentation*.*), logger setup (logger*.*), middleware files, and all source
for log call sites. Detect which surfaces are present; degrade gracefully when
inputs are missing and record which agents will run degraded.
2. AGENTS — spawn the 3 agents in parallel (run_in_background: true), subject to --scope:
• error-tracking (sonnet)
• structured-logging (sonnet, reuses privacy-shield)
• request-response-logging (sonnet, reuses privacy-shield)
--scope limits to a single surface. --quick degrades sonnet to haiku (rarely useful).
3. CONSOLIDATE — collect findings from all agents. Dedup within-run on (agent + type + file + line);
when two findings share file+line+type, keep the higher severity. Then collapse any
findings that still share (file + line) within one agent into a single finding: keep
the highest severity and fold the secondary concern into its description rather than
emitting a second finding (e.g. a PII object logged at info level surfaces once as
logs-pii-object with the level noted — never also as logs-pii-at-info-level).
Severity-rank. Record which agents were skipped (surface not applicable) or errored.
4. REPORT — write .claude/audits/logging-masking-<YYYY-MM-DD>.md using the structured template
(templates/logging-masking-report.template.md): telemetry stack overview, key
configuration table, findings by severity, a manual-review section, and a quick
remediation cheat sheet. If --quick, prepend the quick-mode warning prominently.
5. SUMMARIZE — output a one-screen summary: counts per severity (🔴 / 🟠 / 🟢), the top three
concerns by remediation priority with file/line pointers, whether Sentry
sendDefaultPii is true, and a link to the full report.
--scope flag
--scope all(default) — run all three agents per surface detection.--scope error-tracking— run only theerror-trackingagent.--scope logging— run only thestructured-loggingagent.--scope request— run only therequest-response-loggingagent.
--features flag
Limits the audit to one or more feature modules — scopes call-site scanning and PII-inventory reconciliation to the named features' directories (features/<name>/) and their PLAN.md ## Compliance sections. Accepts a comma-separated list (e.g. --features auth,billing). Default: all features. Useful for a fast re-audit of just the surface you changed.
--quick mode
Degrades the sonnet agents to haiku for a cheaper dev-time spot-check. Rarely useful here — all three agents are already sonnet (mechanical classification work), so the savings are small and the quality loss on call-site judgment is not worth it on a real audit.
The report header will carry this warning when --quick is set:
⚠️ Quick mode used (sonnet agents degraded to haiku). This report is NOT suitable for privacy attestation. Use it as a development feedback loop only.
Failure modes (the audit never hard-fails)
- No error-tracking tool detected →
error-trackingagent reports "no error-tracking tool detected (looked for Sentry / Bugsnag / Rollbar / Honeybadger init) — audit not applicable for this surface." Other agents continue. - No structured logger detected →
structured-loggingagent reports "no structured logger detected — rawconsolecalls scanned (if any)." Continues. - No request-logging middleware detected →
request-response-loggingagent reports "no request-logging middleware detected." Continues. - No declared PII inventory in any feature plan → all agents run in degraded mode (privacy-shield-only detection, no inventory comparison); flagged prominently in the report (
declared_pii_inventory_present: false). - A
Sentry.init.beforeSendfunction with complex/dynamic logic → flagged for manual review; the audit cannot always determine whatbeforeSendactually masks. - An agent errors → recorded in the report's agent execution log; the other agents complete. A single agent error never hard-fails the audit.
Standing audit-finding schema
Every agent emits findings in this shape. Implementers must not invent alternate schemas — the orchestrator consolidates on this contract.
- id: "<AGENT_PREFIX>-<n>" # ERR-1, LOG-2, REQ-3 — sequential within a run
agent: "error-tracking | structured-logging | request-response-logging"
surface: "error-tracking | logging | request-logging"
tool: "sentry | bugsnag | rollbar | honeybadger | pino | winston | bunyan | console | morgan | next-middleware | custom"
severity: "🔴 LEAK | 🟠 AT RISK | 🟢 BEST PRACTICE"
type: "<slug>" # stable kebab-case identity, e.g. send-default-pii-true, set-user-with-pii, logs-pii-object
tool_rule_ref: "<the config option or attribute>" # e.g. "Sentry.init.sendDefaultPii", "pino.redact", "Sentry.beforeSend"
gdpr_ref: "<Art. | null>" # e.g. "GDPR Art. 5(1)(f)", "GDPR Art. 32"
file: "<path | null>"
line: <int | null>
detected_pii_category: "<from privacy-shield: email, phone, ip, etc. | null>"
destination: "<where the PII ends up — sentry.io / log-aggregator / null>"
description: "<what's wrong>"
evidence: "<code/config snippet supporting the finding>"
user_impact: "<what kind of PII leaks and to which destination>"
remediation: "<concrete fix — usually a one-line config or call-site change>"
manual_review_required: <true | false>
What this skill does NOT do
- Does NOT wire into
/pharn-ship. It is standalone and on-demand;/pharn-shipis feature-scope. - Does NOT cover analytics. PostHog
captureproperties and session replay are the scope of/pharn-posthog-masking-audit(the sibling Tier 2 audit) and/pharn-privacy-audit'stelemetryauditor. - Does NOT use review severity semantics (blocking / should / nice). Audit severity here is LEAK / AT RISK / BEST PRACTICE.
- Does NOT re-implement PII detection. The
structured-loggingandrequest-response-loggingagents reuseprivacy-shield's detection viaprocessPrompt(). - Does NOT silence findings that overlap with
/pharn-privacy-audit'stelemetryauditor. This is the focused deep audit; surfacing the same issue with tool-specific guidance is the value-add. - Does NOT auto-fix masking config. Remediation is paste-ready; the human applies it (disabling IP capture or changing redaction can have operational tradeoffs the audit cannot fully judge).
- Does NOT pretend to verify a dynamic
beforeSend, dynamic log content, or runtime config mutations. These are flagged for manual review with a clear reason. - Does NOT mark a finding as 🔴 LEAK on a static-analysis suspicion only — that is 🟠 AT RISK with
manual_review_required: true. - Does NOT expand v1 scope beyond error tracking + structured logging + request logging. Log aggregation tooling, retention policies, transport TLS, and custom logging libraries are deferred.
- Does NOT include any banned language from CLAUDE.md §11.