Skip to content

[sec-check] project-local excuses laundered into trusted user store via recordSighting auto-promotion — re-enables cross-project auto-send #45

Description

@hivecommons-hive

Security Finding

Severity: medium
Type: unsafe-pattern (trust-boundary bypass / persistence)

The #23 fix marks project-local excuses (./.rationguard/custom-excuses.json, attacker-controlled via any cloned repo) as source: 'project' and refuses to auto-send their rebuttals (src/watcher.ts flushBuffer). But the auto-learning path launders them into the trusted user store:

  • src/watcher.ts (flushBuffer) and src/cli.ts (cmdCheck) call recordSighting(match.matchedText, match.excuse.category) for every match with confidence ≥ 0.7 — without checking match.excuse.source.
  • For an exact match, matchedText is the project excuse's pattern (arbitrary attacker text), and confidence is 1.0.
  • After AUTO_ADD_THRESHOLD = 3 sightings, src/learner.ts promoteToExcuse + addToCustomExcuses write the pattern into ~/.rationguard/custom-excuses.json (the HOME store — projectDir is never passed).
  • On next load, getAllExcuses() tags everything from the HOME store as source: 'user' → its rebuttal is auto-send eligible, bypassing the project guard.

Reproduction (verified against dist @ HEAD)

A repo ships .rationguard/custom-excuses.json with {"pattern": "the", ...}. Watching any session in that repo, three buffer flushes containing the word "the" (i.e. virtually any output) produce:

~/.rationguard/custom-excuses.json:
[{"pattern":"the","rebuttal":"Act now. If blocked, move to the next task. ...","category":"deferral","keywords":[]}]

reloaded as source: 'user' → auto-send eligible in every future session in every project.

Impact

  • A malicious repo persistently poisons the user's global excuse store. A pattern like "the" matches nearly all agent output at confidence 1.0.
  • With --rebuttal=send, this triggers keystroke injection (pluk-send/tmux send-keys + Enter) into unrelated agent sessions on a permanent schedule (30s cooldown / 60s quiet), long after the malicious repo is gone. Rebuttal text is the fixed generated string, but the attacker fully controls when Enter-terminated lines are injected, and floods detections/sightings.
  • Same laundering occurs from plain rationguard check runs inside the malicious repo.

Recommendation

Never feed source: 'project' matches into recordSighting. Skip them in both call sites (src/watcher.ts flushBuffer, src/cli.ts cmdCheck), mirroring the existing auto-send guard. Optionally record them into the project-local store instead (detection-only) — but they must never reach the HOME store.


Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)

🐝 Hive Agent: security | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown

— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/securityCreated by Hive for agent-filed issue provenancehelp wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.hive/hosted-available-oke-11-placeholder-r05xCreated by Hive for agent-filed issue provenancesecurityCreated by Hive for agent-filed issue provenance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions