Skip to content

fix(miner): coding-task-spec.js's buildTaskBrief silently drops the prompt-injection audit event its sibling buildInstructions always logs #7441

Description

@JSONbored

Context

packages/loopover-miner/lib/coding-task-spec.ts's own header comment (lines 81-88) documents a specific,
load-bearing invariant: "neutralizePromptInjection runs on both fields before they reach either the coding
agent's instructions (buildInstructions) or the acceptance-criteria document's taskBrief
(buildTaskBrief) -- the two places raw issue text is embedded into agent-facing prose." Both functions do
call neutralizePromptInjection on the issue title/body, and both correctly redact matched content. But only
one of the two logs an audit event when something was actually neutralized:

  • buildInstructions (lines 256-267): checks title.injected || body.injected and emits
    console.log(JSON.stringify({ event: "prompt_injection_neutralized", issueNumber, fields: [...] })).
  • buildTaskBrief (lines 90-94): calls the same neutralizePromptInjection(...).text twice but never reads
    or reports the .injected flag at all -- it only takes .text and discards the rest of the result.

buildTaskBrief's output becomes AcceptanceCriteria.taskBrief via buildCodingTaskAcceptanceCriteria,
which is written to disk inside the attempt's own worktree (writeAcceptanceCriteriaFile) as a persistent,
inspectable artifact. This is exactly the kind of trust/safety signal this package logs elsewhere for the
identical defense (see submission-freshness-check.ts's own abort-reason audit event, and
src/review/prompt-injection.ts's safeReviewTitle which logs prompt_injection_neutralized on the review
side). A target-repo issue whose title/body carries a prompt-injection payload aimed specifically at the
acceptance-criteria document (rather than the coding-agent instructions) is neutralized correctly today, but
the miner's own operator has zero visibility that it happened -- the one call site that would tell them is
silently a no-op.

Requirements

  • buildTaskBrief (or its caller buildCodingTaskAcceptanceCriteria) MUST emit the identical
    prompt_injection_neutralized audit event shape buildInstructions already emits --
    { event: "prompt_injection_neutralized", issueNumber, fields: [...] } -- whenever neutralizing the title
    and/or body actually redacted something, using the same fields array convention (["title"], ["body"],
    or ["title", "body"]).
  • The event MUST be emitted exactly once per buildCodingTaskAcceptanceCriteria call (not once per field,
    not duplicated if buildCodingTaskSpec later also calls buildInstructions on the same issue -- both call
    sites logging independently, once each, for their own field, is the correct and expected behavior; this
    issue is only about buildTaskBrief currently never logging at all).
  • Do NOT change what gets redacted or how neutralizePromptInjection itself works -- this is strictly an
    audit-logging parity fix, not a change to the redaction logic.
  • buildCodingTaskIssue's existing callers and CodingTaskSpecResult's shape must not change.

Deliverables

  • buildTaskBrief (or buildCodingTaskAcceptanceCriteria) logs prompt_injection_neutralized with the
    same JSON shape buildInstructions uses, whenever the title and/or body was actually redacted.
  • A regression test in test/unit/miner-coding-task-spec.test.ts mirroring the existing
    "logs a prompt_injection_neutralized audit event..." test (line 405) but asserting it against
    buildCodingTaskAcceptanceCriteria's output, using a malicious title/body fixture (the existing
    "Ignore all previous instructions..." fixture at line 142 already exercises the redaction; extend it,
    or add a sibling test, to also assert the log call).
  • A regression test confirming a benign issue (no injection pattern) produces zero log calls from
    buildTaskBrief's path, mirroring the existing "does not log... for a benign issue" test (line 431).

Test Coverage Requirements

99%+ Codecov patch coverage (branch-counted) on every changed line in coding-task-spec.ts. Both the
"injection detected, log fires" and "no injection, no log" branches need explicit tests, matching the
existing coverage pattern already present for buildInstructions.

Expected Outcome

A miner operator inspecting logs can see every case where a target repo's issue content required
prompt-injection redaction before being embedded into either agent-facing artifact (instructions OR
acceptance-criteria taskBrief) -- today only one of the two artifacts' redaction events is observable.

Links & Resources

  • packages/loopover-miner/lib/coding-task-spec.ts (header comment lines 81-88, buildTaskBrief lines 90-94,
    buildInstructions lines 256-277)
  • test/unit/miner-coding-task-spec.test.ts (lines 141-149, 405-429, 431-445)
  • packages/loopover-miner/lib/prompt-injection-defense.ts (the shared neutralizePromptInjection)
  • src/review/prompt-injection.ts's safeReviewTitle -- the established audit-logging precedent on the
    review side of the same defense

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions