Skip to content

fix: Node agent-sdk redaction regex drift — non-32-char / non-alphanumeric evt_/emk_ tokens are not masked (potential credential leak) #7

Description

@ConradLu2740

What Happened

The Go CLI and the Node @everme/agent-sdk have drifted on what an evt_/emk_ token looks like. The Go side masks tokens of ≥20 chars and tolerates _/- (explicitly reserving headroom for future key-format changes); the Node side only masks exactly 32 alphanumeric chars. Any token that is shorter/longer than 32 chars or contains _/- passes through completely or partially unmasked into plugin logs, host LLM context, and user-visible errors.

Location:

  • plugins/agent-sdk/src/client.js:29-30 (used by redactError, :54-64):
const evtRe = /evt_[a-zA-Z0-9]{32}/g;
const emkRe = /emk_[a-zA-Z0-9]{32}/g;
  • vs. Go side cli/internal/output/redact.go:12-13:
emkRegex = regexp.MustCompile(`emk_[A-Za-z0-9_\-]{20,}`)
evtRegex = regexp.MustCompile(`evt_[A-Za-z0-9_\-]{20,}`)
  • cli/internal/credential/env.go:24 also accepts emk_[A-Za-z0-9_\-]{16,}, confirming the tolerant shape is expected.

Also, the comment at client.js:25-27 claims the regexes are "case-insensitive on both alphabet AND prefix", but the evt_/emk_ prefixes are actually case-sensitive — comment and implementation disagree.

Steps To Reproduce

  1. Run the SDK's redactError (or any plugin error path) with these synthetic values:
    • emk_ + 24 alnum chars
    • emk_ + 36 alnum chars with -
    • emk_ + 36 alnum chars
  2. Observe output (node-verified):
Input Result
emk_ + 24 alnum chars not redacted at all
emk_ + 36 alnum chars with - not redacted at all
emk_ + 36 alnum chars partially leaked: emk_a1b2_REDACTEDe7 (tail 4 chars in clear)
emk_ + 32 hex chars (current format) redacted correctly (only safe case)

Expected Behavior

All evt_*/emk_* shapes handled by the Go side must also be masked by the Node SDK, since agent-sdk is the shared base of all plugins (memory-mcp, claude-code, codex, openclaw).

Suggested Fix

const tokenRe = /(?:evt_|emk_)[A-Za-z0-9_\-]{20,}/g;

Plus regression tests for: 24-char, 36-char with -, 36-char pure alnum, and mixed-case prefix — asserting full masking.

Why It Matters

Today the backend issues 32-char lowercase hex, so nothing leaks. But the Go side explicitly documents headroom for a "future backend key-format tweak (Base32, mixed case, longer payloads)". The moment the backend rotates the key format, every plugin error surface (hook stderr diagnostics, MCP tool error text, EvermeError.message) starts leaking full credentials to hosts (Claude Code, Codex, OpenClaw) and user logs.

Environment

  • OS: macOS 26.4 (arm64)
  • evercli --version: 0.31.2
  • Package or plugin: @everme/agent-sdk@0.4.2 (also affects memory-mcp 0.4.2, claude-code 0.4.2, codex 0.4.2, openclaw 0.4.2)

Logs

No real emk_*/evt_* values used in this report; all examples are synthetic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions