Skip to content

Miner dashboard change/rerun text isn't redacted for secret tokens #448

Description

@galuis116

Summary

sanitizePublicText in src/services/miner-dashboard-recommendations.ts (new in #423) is the public-safety boundary for the miner-dashboard change labels and rerun reasons. It strips local filesystem paths and a list of sensitive words (wallets, hotkeys, trust scores, rewards, scoreability, …) but has no rule for secret tokens (ghp_, github_pat_, gts_, glpat-, sk-). The output is served on /v1/app/miner-dashboard.

Evidence

// src/services/miner-dashboard-recommendations.ts:383
function sanitizePublicText(value: string): string {
  return value
    .replace(LOCAL_PATH, "[local path]")
    .replace(FORBIDDEN_PUBLIC_TEXT, "private context")
    .replace(/s+/g, " ")
    .trim();
}

FORBIDDEN_PUBLIC_TEXT (line 43) and LOCAL_PATH (line 45) contain no token patterns. Yet the module's own test declares tokens forbidden in this output:

// test/unit/miner-dashboard-recommendations.test.ts:11
const FORBIDDEN_PUBLIC_CHANGE_TEXT = /|github_pat|ghp_/i;
// line 83: expect(...).not.toMatch(FORBIDDEN_PUBLIC_CHANGE_TEXT)

The assertion passes only because no fixture injects a token — no code path actually removes one.

Inconsistent with the established pattern

Every other public/role-facing sanitizer redacts tokens:

  • src/services/agent-action-explanation-card.ts:11github_pat_…|gh[pousr]_… + local paths
  • src/services/weekly-value-report.ts:413.replace(/�(?:ghp_|github_pat_|gts_|glpat-|sk-)[A-Za-z0-9_=-]{8,}/g, "<redacted-token>")
  • src/services/control-panel-roles.ts:257 — identical token rule

miner-dashboard-recommendations.ts is the outlier.

Impact

The change/rerun metadata surfaces free-text decision-pack fields (actionPortfolio.topActions[].rerunWhen, scoreBlocker codes, recommendation, roleContext, manifest summaries). A token landing in any of those is emitted verbatim on /v1/app/miner-dashboard — the defense-in-depth case the sibling services already guard against.

Suggested fix

const FORBIDDEN_TOKEN = /(?:ghp_|github_pat_|gts_|glpat-|sk-)[A-Za-z0-9_=-]{8,}/g;

function sanitizePublicText(value: string): string {
  return value
    .replace(LOCAL_PATH, "[local path]")
    .replace(FORBIDDEN_TOKEN, "private context")
    .replace(FORBIDDEN_PUBLIC_TEXT, "private context")
    .replace(/s+/g, " ")
    .trim();
}

Add a fixture that injects a ghp_… token into a surfaced field (e.g. rerunWhen) so the existing assertion actually exercises token redaction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    slopAI slop and/or attempts to game additional points via manipulation or alt profiles.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions