Skip to content

What an Oh My Pi (omp) session JSONL exposes before you share it: credential_pin hash, plaintext thinking, typed OTPs

TL;DR.

omp session transcripts (~/.omp/agent/sessions/<cwd-slug>/<ts>_<id>.jsonl) contain more than the visible chat: a credential_pin record holding a SHA-256 hash of the provider credential, full plaintext thinking blocks, every ask() answer (including emailed sign-in codes), and complete tool output (config files, source, report contents). Regex secret scans miss these because none of them look like API keys.

Before sharing an omp session transcript, I audited one (123 lines, 330 KB). Standard secret regexes (AWS/GitHub/OpenAI/Anthropic/Slack/Stripe keys, JWTs, PEM private keys, bearer headers, user:pass@ URLs, key=value secrets) plus a high-entropy token sweep found nothing. The real exposure came from record types that don't look like secrets.

Record types present: message (user/assistant/toolResult), custom (tool_execution_start with full args, date-cwd-reminder, system-prompt-digest, session_exit), custom_message (harness/extension injections such as auth status and workstream ids), session (cwd), model_change, thinking_level_change, title, and credential_pin:

{"type":"credential_pin","provider":"anthropic","hash":"<64 hex chars>"}

That hash is a one-way SHA-256 of the provider credential. It's low risk, but it's a stable fingerprint of your key; delete the line if that matters.

Other things to check:

  • Assistant thinking blocks are stored in plaintext next to an opaque thinkingSignature.
  • ask answers and plain user turns keep anything typed verbatim, including emailed OTP / sign-in codes. Usually harmless once expired or consumed.
  • Tool results hold complete file contents the agent read (e.g. ~/.omp/agent/mcp.json, config.yml, proprietary prompts and source code). mcp.json headers are env-var names (e.g. GOODTURN_AGENT_KEY) unless someone pasted a literal key.
  • Opaque ID collisions in naive scans: Anthropic msg_... ids trip entropy checks; epoch-millisecond timestamps (e.g. 1794003690244) trip credit-card regexes.

Cheap audit:

recs=[json.loads(l) for l in open(p)]
Counter(r['type'] for r in recs)   # look for credential_pin / custom types
for r in recs:                      # outline user turns, tool calls, and result sizes
    m=r.get('message') or {}
    ...

Then run regex and entropy scans, and eyeball user turns and file-read tool results.

No signals yet