Skip to content

fix(mothership): redact file text before grep clips or splits it - #8929

Closed
waleedlatif1 wants to merge 1 commit into
stagingfrom
fix/grep-redact-before-truncate
Closed

waleedlatif1 wants to merge 1 commit into
stagingfrom
fix/grep-redact-before-truncate

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Model egress redacts whole secrets only. grep clipped each line at 2,000 characters and split files into lines before egress ran, so a known secret that straddled the clip leaked its prefix, and each line of a multi-line secret (a PEM key, for example) crossed as an unrecognizable fragment.
  • grep now redacts each resource's full text through the invocation's provenance (the same propagated set egress uses) before splitting, matching and clipping. The clip also backs off to the start of a redaction marker, so it never leaves half a {{NAME}} or [REDACTED_SECRET].
  • Matching now runs on redacted text, so grep --count <guess> can no longer be used to confirm a secret value one prefix at a time.
  • A resource whose text can't be redacted is skipped and reported as incomplete; it isn't searched raw.
  • The engine runtime now carries the invocation's resolvedSecretTraceRegistry.
  • JSON and JSONL parse errors reach Chat as the read's error. They no longer quote a clipped excerpt of the file: V8's quoted input excerpt is stripped, and JSONL no longer appends the first 100 characters of the bad line.

Type of Change

  • Bug fix

Testing

  • New cases in file-provenance.test.ts run through the real CLI handler and inspectToolResultForCopilot: a secret straddling the clip, a secret whose marker would straddle it, a secret wholly past it, several secrets around the cut, and a multi-line secret. They check that no 4-character prefix or suffix and no partial marker survives. The straddling, marker, multiple-secret and multi-line cases fail on the old code; the wholly-past case passed before too and guards the boundary.
  • Reverting each guard separately turns the matching tests red: redact-first, and the marker-safe cut.
  • New json-parser.test.ts cases: invalid JSON and JSONL never quote the file. Both fail on the old code.
  • bunx vitest run lib/mothership/agent-cli lib/file-parsers lib/workspace-files passes (1,120 tests).
  • Root bun run test passed except 3 files that hit 10s/60s timeouts under full parallel load. Those 3 files pass when run alone and are unrelated.
  • bun run lint, bun run type-check, bun run check:audits (59 audits), and the block-registry check all pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Model egress redacts whole secrets only, so grep's 2,000-character line clip and its per-line split could hand it a fragment of a known secret it cannot recognize. Grep now redacts each resource's full text through the invocation's provenance before splitting, matching and clipping, and the clip never cuts through a redaction marker. JSON and JSONL parse errors no longer quote a clipped excerpt of the file.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files

Confidence score: 2/5

  • In agent-cli/types.ts, grep can run without provenance, and redactForModel leaves text unchanged when the registry is absent, so clipped output can expose secret fragments. Fail closed when provenance is missing.
  • In json-parser.ts, describeSyntaxError can still send the first character of a secret to Chat in V8’s Unexpected token prefix. Return a generic syntax diagnostic instead.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/lib/mothership/agent-cli/types.ts">

<violation number="1" location="apps/sim/lib/mothership/agent-cli/types.ts:44">
P1: This optional field lets grep run without provenance, and `redactForModel` returns text unchanged when the registry is absent, so clipping can emit secret fragments. Fail closed when provenance is missing or require and populate the registry before this engine runs.</violation>
</file>

<file name="apps/sim/lib/file-parsers/json-parser.ts">

<violation number="1" location="apps/sim/lib/file-parsers/json-parser.ts:225">
P2: `describeSyntaxError` removes the quoted excerpt but leaves V8’s `Unexpected token 's'` prefix, so malformed JSON starting with a secret still sends its first character to Chat. Return a generic syntax diagnostic instead.</violation>
</file>

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Turn on auto-fix | Re-trigger cubic

* The invocation's secret provenance, which model egress redacts the result with. Egress
* matches whole secrets, so an engine that clips or splits text it read redacts it here first.
*/
resolvedSecretTraceRegistry?: ResolvedSecretTraceRegistry

@cubic-dev-ai cubic-dev-ai Bot Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This optional field lets grep run without provenance, and redactForModel returns text unchanged when the registry is absent, so clipping can emit secret fragments. Fail closed when provenance is missing or require and populate the registry before this engine runs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/mothership/agent-cli/types.ts, line 44:

<comment>This optional field lets grep run without provenance, and `redactForModel` returns text unchanged when the registry is absent, so clipping can emit secret fragments. Fail closed when provenance is missing or require and populate the registry before this engine runs.</comment>

<file context>
@@ -36,6 +37,11 @@ export interface AgentCliRuntime {
+   * The invocation's secret provenance, which model egress redacts the result with. Egress
+   * matches whole secrets, so an engine that clips or splits text it read redacts it here first.
+   */
+  resolvedSecretTraceRegistry?: ResolvedSecretTraceRegistry
   signal?: AbortSignal
 }
</file context>
Fix with cubic

* through a secret would carry the part that survived the cut.
*/
function describeSyntaxError(error: unknown): string {
return getErrorMessage(error, 'Unknown error').replace(QUOTED_INPUT_EXCERPT, '')

@cubic-dev-ai cubic-dev-ai Bot Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: describeSyntaxError removes the quoted excerpt but leaves V8’s Unexpected token 's' prefix, so malformed JSON starting with a secret still sends its first character to Chat. Return a generic syntax diagnostic instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/file-parsers/json-parser.ts, line 225:

<comment>`describeSyntaxError` removes the quoted excerpt but leaves V8’s `Unexpected token 's'` prefix, so malformed JSON starting with a secret still sends its first character to Chat. Return a generic syntax diagnostic instead.</comment>

<file context>
@@ -213,6 +213,18 @@ export function stripJsonComments(text: string): string {
+ * through a secret would carry the part that survived the cut.
+ */
+function describeSyntaxError(error: unknown): string {
+  return getErrorMessage(error, 'Unknown error').replace(QUOTED_INPUT_EXCERPT, '')
+}
+
</file context>
Suggested change
return getErrorMessage(error, 'Unknown error').replace(QUOTED_INPUT_EXCERPT, '')
return 'Invalid JSON syntax'
Fix with cubic

@greptile-apps

greptile-apps Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium impact] Redacts secrets before clipping or splitting file text in grep.

Fix the incorrect line numbers after multi-line secrets before merging.

Findings

  1. P1 Matches point to wrong lines ▶

Summary

This PR redacts full resource text before grep matches, splits, or clips it. It also removes quoted file excerpts from JSON and JSONL parse errors.

  • Grep redacts file text before it searches or clips lines.
  • Invalid JSON and JSONL errors no longer quote file text.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Read resource text and secret provenance] --> B[Copy propagated secret entries]
  B --> C[Redact full resource text]
  C --> D{Safe to search?}
  D -->|No| E[Skip resource and report incomplete search]
  D -->|Yes| F[Split redacted text into lines]
  F --> G[Match and select context]
  G --> H[Clip without splitting markers]
  H --> I[Check result before sending to model]
Loading

Reviews (1) · Last reviewed commit: "fix(mothership): redact file text before..." · Reviewed by Greptile

)
continue
}
const lines = text.split('\n')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Matches point to wrong lines

Replacing a multi-line secret with one marker removes its newlines before grep numbers the lines. In the new fixture, searching for config end reports line 3 instead of line 6. Every later match shifts too, and context windows cover different source lines. Following a reported location can therefore read the wrong part of the file.

Keep redaction before matching, but preserve the original line positions or map the redacted positions back to them.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Closing: this fix is being consolidated with the other file-provenance fixes into a single PR with one shared abstraction. The branch is kept for reference.

@waleedlatif1
waleedlatif1 deleted the fix/grep-redact-before-truncate branch October 12, 2026 18:13
@vercel

vercel Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 12, 2026 6:44pm UTC

Request Review

This branch was previously deployed

1 inactive deployment
Preview — d4870bd2 Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant