Skip to content

Redact phone numbers and webhook details from default logs #61

Description

@Justinabox

Summary

Several default INFO/WARNING log paths include phone numbers, webhook URLs, or raw modem response lines. In server.py, the process enables INFO logging by default, so a normal HTTP/server deployment can write caller/SMS metadata to logs even though the project north-star explicitly calls for "no secrets in logs" and PII-safe operations.

This is a production-readiness/security gap for unattended Pi deployments used for MFA/SMS automation: logs are commonly shipped, copied into bug reports, or exposed to service managers.

Evidence

Baseline is healthy:

$ git diff --check
# exit 0

$ PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q
361 passed in 4.23s

Minimal repro for SMSService.send at INFO level using a fake executor:

$ PYTHONPATH=. uv run --no-project --with pyserial-asyncio python - <<'PY'
import asyncio, logging
from callstack.sms.service import SMSService
from callstack.events.bus import EventBus
from callstack.protocol.executor import ATResponse

class FakeAT:
    async def execute(self, command, **kwargs):
        return ATResponse(success=True, lines=['>'] if command.startswith('AT+CMGS') else ['OK'])
    async def send_data(self, data, **kwargs):
        return ATResponse(success=True, lines=['+CMGS: 7', 'OK'])

async def main():
    logging.basicConfig(level=logging.INFO, format='%(name)s %(levelname)s %(message)s')
    svc = SMSService(FakeAT(), EventBus())
    await svc.send('+155****4567', 'hello')

asyncio.run(main())
PY
callstack.sms INFO SMS sent to +155****4567 (ref: 7)

The number above is a fake masked placeholder, but the code logs the real to value in production.

Static inspection found additional PII-adjacent log paths:

  • server.py:268-270 sets default server logging to INFO.
  • server.py:217-219 logs webhook POST URLs on failures.
  • server.py:227-229 logs session.number for incoming calls.
  • callstack/sms/service.py:172-173 logs outbound SMS recipient.
  • callstack/sms/service.py:199-201 logs inbound SMS sender.
  • callstack/voice/service.py:69-70, :93-94, and :165-166 log dial/caller numbers.
  • callstack/modem.py:168-179, callstack/voice/service.py:148-149, and callstack/protocol/urc.py:70-71 can log raw response/URC/exception text, which may contain modem identifiers or message fragments depending on failure mode.

Expected behavior

Default logs should be safe to attach to support issues or ship to system logging without exposing real phone numbers, SIM identifiers, SMS bodies/passcodes, webhook URLs, or raw modem payloads.

Suggested fix direction

  1. Add a small redaction helper for phone-like strings, URLs with tokens/query strings, SMS bodies/passcode-looking fields, and raw AT response lines.
  2. Use structured fields where possible and log redacted values by default, e.g. last-2/last-4 only or stable hashes when correlation is needed.
  3. Keep verbose raw AT/URC dumps behind an explicit unsafe debug flag if needed for hardware troubleshooting.
  4. Add tests with fake sensitive-looking strings in logs and assert caplog.text excludes the raw values.

Acceptance criteria

  • Default INFO/WARNING/ERROR logs do not include full phone numbers, SMS bodies/passcodes, webhook URLs, SIM/IMEI-like identifiers, or raw modem response lines containing those values.
  • Existing CLI tests that assert private SMS fields are not printed continue to pass.
  • New caplog tests cover SMS send/receive, voice caller/dial logs, webhook failure logs, and at least one raw-response warning path.
  • Documentation explains how to enable deeper hardware diagnostics safely.

Verification gates

git diff --check
PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions