Skip to content

fix: redact standalone apikey_ credentials (#147) - #242

Merged
kunchenguid merged 3 commits into
kunchenguid:mainfrom
WTF-Am-ID:fm/up-backpass-147
Oct 28, 2026
Merged

kunchenguid merged 3 commits into
kunchenguid:mainfrom
WTF-Am-ID:fm/up-backpass-147

Conversation

@WTF-Am-ID

Copy link
Copy Markdown
Contributor

Intent

1 p1-p7 codex only no cross model review

Context: this task is upstream scan 3 pick P2: upstream issue #147 in kunchenguid/backpass. The owner approved fixing scan picks P1-P7 upstream through PRs, written and reviewed by Codex only, with no cross-model review. Scan notes for this pick:

Issue: #147

Backpass leaves standalone lowercase and uppercase apikey_ credentials unredacted.
Size S.
Contract class: restore.
Recorded triage.

Current-source evidence: Pinned Backpass src/redact.js:8-28 has specific token grammars and assignment handling but no standalone apikey_ grammar.

Competing-work check: No exact target across all 18 open proposal bodies/titles. All 18 changed-file inventories were checked. Our #237 touches src/redact.js to return replacement offsets, but its actual diff keeps PATTERNS unchanged and contains no apikey token. It does not implement this missing grammar. Coordinate the ordinary rebase if the offset work lands first.

Closure test: Use fake token strings only. Exercise redact() with lowercase, uppercase, punctuation-delimited and multiline apikey_ plus the maintainer's token-length floor. Verify no full token survives in the distilled prompt/cache path. Pin short-token and ordinary-word negative controls and existing assignment/token formats. Removing the new grammar must make the regression fail. Run the relevant Node tests, then the repository's pnpm run check.

What Changed

  • Redact standalone apikey_ credentials case-insensitively with a 16-character suffix minimum, after assignment redaction to keep secret values protected.
  • Add regression coverage for punctuation, multiline input, short-token and ordinary-word controls, assignment handling, and credential removal from traces and cached analysis prompts.

Risk Assessment

✅ Low: The narrow matcher addition preserves existing provider rules, and the revised ordering resolves the assignment collision without expanding scope.

Testing

Both permitted test files and all live prompt-cache scenarios passed. Baseline, grammar-removal, and prior-revision probes reproduced the reported failures. Product outputs were retained. Cleanup was rejected by the command guard, leaving ignored scratch under .local-test-147/.

  • Live validation: ✅ go - 5 of 5 scenarios driven live against the product
Scenario Result Live Evidence
Analyze standalone credentials with varied case, punctuation, newlines, and a 16-character suffix; cached prompt contains redaction markers ✅ pass live CLI-generated analysis prompt, cases C01–C09
Analyze short tokens, ordinary words, embedded prefixes, and benign token counts; cached prompt preserves them ✅ pass live CLI-generated analysis prompt, cases C10–C16
Analyze long lowercase and uppercase APIKEY assignment names using equals, colons, and quoted values; assignment secrets never survive ✅ pass live CLI-generated analysis prompt, cases C17–C32; assignment-regression.json
Analyze existing provider tokens, private keys, and ordinary secret assignments; established redaction behavior remains intact ✅ pass live CLI-generated analysis prompt, cases C33–C44
Analyze credentials and colliding assignments in tool commands and results; neither reaches the cached prompt ✅ pass live CLI-generated analysis prompt, Bash tool input and output
Evidence: Actual CLI-generated analysis prompt
<!-- backpass:self-session -->
You are auditing one past agent session against the repository's agent memory file.

Your job is NOT to review the code. It is to measure how well the memory file's
instructions actually steered this session, and to spot mistakes an instruction could
have prevented. This is the loss signal for a backward pass over the memory file.

## The memory file under audit: MEMORY.md

Each instruction has a stable id in [brackets]. Refer to instructions ONLY by these ids.

[AG-001] (10 tok, L3) <Instructions>
- Run the project tests before delivery.

## Project skills (load-on-trigger)

These skills exist in the repo. Each one's body is loaded only when its trigger fires,
so it is NOT shown here - only the trigger description is. If a mistake you found is
covered by one of these skills' content, it is a failed trigger: still report the gap,
and name that skill in `coveredBySkill`. Open the skill's file (path in parentheses)
only when you need its body to confirm the coverage.

(this repo has no skills)

## Gaps already on the books

Earlier sessions reported these gaps; each has a stable id. If a gap you found is the
same underlying gap as one below - one instruction would prevent both - cite that id in
`matchesGap` and still describe what you saw. A gap that matches nothing here is new:
omit `matchesGap`.

(none yet)

## The distilled session trace

Tool calls are one-line summaries and tool output is truncated. The raw transcript path
is at the end of the trace: open it ONLY if a specific claim you want to make cannot be
verified from the distilled trace. Reading it is allowed but costs time, so do not do it
by default. Set `usedRawTranscript` accordingly.

# session codex-synthetic-redaction-probe
harness: codex
date: 2026-10-28T13:11:23.989Z
cwd: ~/.no-mistakes-upstream-codex/worktrees/00c42fff1637/01M619JAT2F2MH08ZZX7R87MT6/.local-test-147/repo-v2
association: tier 1 (exact)

\### turn 1 · user
<<C01>>
[redacted:API_KEY]
<</C01>>
<<C02>>
([redacted:API_KEY]), next.
<</C02>>
<<C03>>
[redacted:API_KEY]
<</C03>>
<<C04>>
([redacted:API_KEY]), next.
<</C04>>
<<C05>>
[redacted:API_KEY]
<</C05>>
<<C06>>
([redacted:API_KEY]), next.
<</C06>>
<<C07>>
[redacted:API_KEY]
<</C07>>
<<C08>>
([redacted:API_KEY]), next.
<</C08>>
<<C09>>
before
[redacted:API_KEY]
[redacted:API_KEY]
after
<</C09>>
<<C10>>
apikey
<</C10>>
<<C11>>
apikey_documentation
<</C11>>
<<C12>>
apikey_aaaaaaaaaaaaaaa
<</C12>>
<<C13>>
APIKEY_BBBBBBBBBBBBBBB
<</C13>>
<<C14>>
notapikey_vvvvvvvvvvvvvvvvvvvv
<</C14>>
<<C15>>
max_output_tokens:12000,yield_time_ms:1000
<</C15>>
<<C16>>
usage: { prompt_tokens: 1234, completion_tokens: 56 }
<</C16>>
<<C17>>
[redacted:API_KEY]=[redacted]
<</C17>>
<<C18>>
[redacted:API_KEY]=[redacted]
<</C18>>
<<C19>>
[redacted:API_KEY]=[redacted]
<</C19>>
<<C20>>
[redacted:API_KEY]=[redacted]
<</C20>>
<<C21>>
[redacted:API_KEY]=[redacted]
<</C21>>
<<C22>>
[redacted:API_KEY]=[redacted]
<</C22>>
<<C23>>
[redacted:API_KEY]=[redacted]
<</C23>>
<<C24>>
[redacted:API_KEY]=[redacted]
<</C24>>
<<C25>>
[redacted:API_KEY]=[redacted]
<</C25>>
<<C26>>
[redacted:API_KEY]=[redacted]
<</C26>>
<<C27>>
[redacted:API_KEY]=[redacted]
<</C27>>
<<C28>>
[redacted:API_KEY]=[redacted]
<</C28>>
<<C29>>
[redacted:API_KEY]=[redacted]
<</C29>>
<<C30>>
[redacted:API_KEY]=[redacted]
<</C30>>
<<C31>>
[redacted:API_KEY]=[redacted]
<</C31>>
<<C32>>
[redacted:API_KEY]=[redacted]
<</C32>>
<<C33>>
[redacted:ANTHROPIC_KEY]
<</C33>>
<<C34>>
[redacted:OPENAI_KEY]
<</C34>>
<<C35>>
[redacted:OPENROUTER_KEY]
<</C35>>
<<C36>>
[redacted:API_KEY]
<</C36>>
<<C37>>
[redacted:GITHUB_TOKEN]
<</C37>>
<<C38>>
[redacted:SLACK_TOKEN]
<</C38>>
<<C39>>
[redacted:AWS_ACCESS_KEY_ID]
<</C39>>
<<C40>>
[redacted:JWT]
<</C40>>
<<C41>>
[redacted:PRIVATE_KEY]
<</C41>>
<<C42>>
API_KEY=[redacted]
<</C42>>
<<C43>>
MY_SECRET=[redacted]
<</C43>>
<<C44>>
export GITHUB_TOKEN=[redacted:GITHUB_TOKEN]
<</C44>>

\### turn 2 · assistant
I will run the project tests as instructed.

\### turn 3 · user
Please include tool input and output in the verification.

tool: Bash "[redacted:API_KEY]" -> [redacted:API_KEY]
tool: Bash "[redacted:API_KEY]=[redacted]" -> [redacted:API_KEY]=[redacted]
\### turn 4 · assistant
The verification uses synthetic data only.

---
raw transcript: ~/.no-mistakes-upstream-codex/worktrees/00c42fff1637/01M619JAT2F2MH08ZZX7R87MT6/.local-test-147/home-v2/.codex/sessions/2026/10/28/rollout-synthetic-redaction-probe.jsonl
Tool calls above are one-line summaries and tool output is truncated. Open the raw
transcript only if a specific claim needs the full text.


## What to report

Return ONE JSON object and nothing else. No prose before or after, no markdown fence.

`` `
{
  "positive":  [{"instruction": "AG-042", "moment": "turn 12", "effect": "what following it achieved", "quote": "verbatim text from the trace"}],
  "negative":  [{"instruction": "AG-017", "moment": "turn 3",  "effect": "what happened and what it cost", "class": "harm|non-compliance|irrelevant", "quote": "verbatim text from the trace"}],
  "gaps":      [{"mistake": "what went wrong", "proposedInstruction": "one sentence that would have prevented it", "recurrenceRisk": "high|medium|low", "domain": "project|orchestration", "matchesGap": "<id from the list above, omit when new>", "coveredBySkill": "<skill name from the skills list, omit when none covers it>", "quote": "verbatim text from the trace"}],
  "usedRawTranscript": false
}
`` `

Rules, in order of importance:

1. **Every item needs a verbatim `quote` copied exactly from the trace.** Items without
   a real quote are discarded downstream, so an unquotable claim is wasted work.
2. **Negative evidence is the most valuable.** A visible violation, misreading, or
   ignored instruction outranks a dozen "it went fine" observations.
3. **`class` states what a negative means, and the difference decides the instruction's
   fate.** `harm`: the agent FOLLOWED the instruction and following it caused damage or
   cost - evidence against the instruction itself. `non-compliance`: the agent ignored
   or violated the instruction - evidence the instruction failed to steer, which argues
   for reinforcing it, never for deleting it. `irrelevant`: on inspection the moment
   does not actually bear on this instruction. Never report a skipped rule as `harm`.
4. **`domain` states what caused a gap.** A gap is `orchestration` when the mistake was
   not caused by this repository, but by an external agent harness or tooling that
   orchestrated the task (a task brief, a supervisor's process, the harness itself - by
   way of illustration only, not a list to match against); every other gap is `project`.
   Ask the causal question, not which category the wording resembles. If this
   repository IS the orchestrating tool, mistakes in how it orchestrated are `project`.
   Orchestration gaps are counted but never proposed into this repository's memory file.
5. **Do not confabulate influence.** Only call something positive when the trace shows
   the agent doing the specific thing the instruction asks for. An outcome that would
   have happened anyway is not evidence.
6. `gaps` are mistakes NOT covered by any current instruction. If an instruction exists
   and was ignored, that is `negative` with `class: "non-compliance"`, not a gap. A
   mistake covered only by a SKILL's content is still a gap - skills have no
   instruction ids - but cite the skill in `coveredBySkill`: that is a failed trigger,
   and the fix is that skill's description, not new memory-file text.
7. `proposedInstruction` must be one imperative sentence, specific enough to act on and
   general enough to apply beyond this one session.
8. An empty array is a valid and useful answer. Report nothing rather than something weak.
Evidence: Synthetic inputs and observed redaction outputs
{
  "revision": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
  "checkpoint": "Actual CLI-generated prompt persisted; stopped before model execution. No stub backend used.",
  "cases": [
    {
      "id": "C01",
      "group": "standalone",
      "input": "apikey_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "expected": "[redacted:API_KEY]",
      "actual": "[redacted:API_KEY]",
      "result": "pass"
    },
    {
      "id": "C02",
      "group": "standalone",
      "input": "(apikey_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa), next.",
      "expected": "([redacted:API_KEY]), next.",
      "actual": "([redacted:API_KEY]), next.",
      "result": "pass"
    },
    {
      "id": "C03",
      "group": "standalone",
      "input": "APIKEY_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
      "expected": "[redacted:API_KEY]",
      "actual": "[redacted:API_KEY]",
      "result": "pass"
    },
    {
      "id": "C04",
      "group": "standalone",
      "input": "(APIKEY_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB), next.",
      "expected": "([redacted:API_KEY]), next.",
      "actual": "([redacted:API_KEY]), next.",
      "result": "pass"
    },
    {
      "id": "C05",
      "group": "standalone",
      "input": "ApiKeY_aB3_-aB3_-aB3_-x",
      "expected": "[redacted:API_KEY]",
      "actual": "[redacted:API_KEY]",
      "result": "pass"
    },
    {
      "id": "C06",
      "group": "standalone",
      "input": "(ApiKeY_aB3_-aB3_-aB3_-x), next.",
      "expected": "([redacted:API_KEY]), next.",
      "actual": "([redacted:API_KEY]), next.",
      "result": "pass"
    },
    {
      "id": "C07",
      "group": "standalone",
      "input": "apikey_cccccccccccccccc",
      "expected": "[redacted:API_KEY]",
      "actual": "[redacted:API_KEY]",
      "result": "pass"
    },
    {
      "id": "C08",
      "group": "standalone",
      "input": "(apikey_cccccccccccccccc), next.",
      "expected": "([redacted:API_KEY]), next.",
      "actual": "([redacted:API_KEY]), next.",
      "result": "pass"
    },
    {
      "id": "C09",
      "group": "standalone",
      "input": "before\napikey_dddddddddddddddd\nAPIKEY_EEEEEEEEEEEEEEEE\nafter",
      "expected": "before\n[redacted:API_KEY]\n[redacted:API_KEY]\nafter",
      "actual": "before\n[redacted:API_KEY]\n[redacted:API_KEY]\nafter",
      "result": "pass"
    },
    {
      "id": "C10",
      "group": "negative controls",
      "input": "apikey",
      "expected": "apikey",
      "actual": "apikey",
      "result": "pass"
    },
    {
      "id": "C11",
      "group": "negative controls",
      "input": "apikey_documentation",
      "expected": "apikey_documentation",
      "actual": "apikey_documentation",
      "result": "pass"
    },
    {
      "id": "C12",
      "group": "negative controls",
      "input": "apikey_aaaaaaaaaaaaaaa",
      "expected": "apikey_aaaaaaaaaaaaaaa",
      "actual": "apikey_aaaaaaaaaaaaaaa",
      "result": "pass"
    },
    {
      "id": "C13",
      "group": "negative controls",
      "input": "APIKEY_BBBBBBBBBBBBBBB",
      "expected": "APIKEY_BBBBBBBBBBBBBBB",
      "actual": "APIKEY_BBBBBBBBBBBBBBB",
      "result": "pass"
    },
    {
      "id": "C14",
      "group": "negative controls",
      "input": "notapikey_vvvvvvvvvvvvvvvvvvvv",
      "expected": "notapikey_vvvvvvvvvvvvvvvvvvvv",
      "actual": "notapikey_vvvvvvvvvvvvvvvvvvvv",
      "result": "pass"
    },
    {
      "id": "C15",
      "group": "negative controls",
      "input": "max_output_tokens:12000,yield_time_ms:1000",
      "expected": "max_output_tokens:12000,yield_time_ms:1000",
      "actual": "max_output_tokens:12000,yield_time_ms:1000",
      "result": "pass"
    },
    {
      "id": "C16",
      "group": "negative controls",
      "input": "usage: { prompt_tokens: 1234, completion_tokens: 56 }",
      "expected": "usage: { prompt_tokens: 1234, completion_tokens: 56 }",
      "actual": "usage: { prompt_tokens: 1234, completion_tokens: 56 }",
      "result": "pass"
    },
    {
      "id": "C17",
      "group": "assignment collision",
      "input": "apikey_openrouter_production = hunter2hunter2",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C18",
      "group": "assignment collision",
      "input": "apikey_openrouter_production = \"hunter2hunter2,secret\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C19",
      "group": "assignment collision",
      "input": "apikey_openrouter_production = 'hunter2hunter2,secret'",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C20",
      "group": "assignment collision",
      "input": "apikey_openrouter_production = \"hunter2\nhunter2\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C21",
      "group": "assignment collision",
      "input": "apikey_openrouter_production : hunter2hunter2",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C22",
      "group": "assignment collision",
      "input": "apikey_openrouter_production : \"hunter2hunter2,secret\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C23",
      "group": "assignment collision",
      "input": "apikey_openrouter_production : 'hunter2hunter2,secret'",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C24",
      "group": "assignment collision",
      "input": "apikey_openrouter_production : \"hunter2\nhunter2\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C25",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION = hunter2hunter2",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C26",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION = \"hunter2hunter2,secret\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C27",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION = 'hunter2hunter2,secret'",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C28",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION = \"hunter2\nhunter2\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C29",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION : hunter2hunter2",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C30",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION : \"hunter2hunter2,secret\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C31",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION : 'hunter2hunter2,secret'",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C32",
      "group": "assignment collision",
      "input": "APIKEY_OPENROUTER_PRODUCTION : \"hunter2\nhunter2\"",
      "expected": "[redacted:API_KEY]=[redacted]",
      "actual": "[redacted:API_KEY]=[redacted]",
      "result": "pass"
    },
    {
      "id": "C33",
      "group": "existing formats",
      "input": "sk-ant-aaaaaaaaaaaaaaaa",
      "expected": "[redacted:ANTHROPIC_KEY]",
      "actual": "[redacted:ANTHROPIC_KEY]",
      "result": "pass"
    },
    {
      "id": "C34",
      "group": "existing formats",
      "input": "sk-proj-bbbbbbbbbbbbbbbb",
      "expected": "[redacted:OPENAI_KEY]",
      "actual": "[redacted:OPENAI_KEY]",
      "result": "pass"
    },
    {
      "id": "C35",
      "group": "existing formats",
      "input": "sk-or-v1-cccccccccccccccc",
      "expected": "[redacted:OPENROUTER_KEY]",
      "actual": "[redacted:OPENROUTER_KEY]",
      "result": "pass"
    },
    {
      "id": "C36",
      "group": "existing formats",
      "input": "sk-dddddddddddddddddddddddddddddddd",
      "expected": "[redacted:API_KEY]",
      "actual": "[redacted:API_KEY]",
      "result": "pass"
    },
    {
      "id": "C37",
      "group": "existing formats",
      "input": "ghp_eeeeeeeeeeeeeeee",
      "expected": "[redacted:GITHUB_TOKEN]",
      "actual": "[redacted:GITHUB_TOKEN]",
      "result": "pass"
    },
    {
      "id": "C38",
      "group": "existing formats",
      "input": "xoxb-ffffffffff",
      "expected": "[redacted:SLACK_TOKEN]",
      "actual": "[redacted:SLACK_TOKEN]",
      "result": "pass"
    },
    {
      "id": "C39",
      "group": "existing formats",
      "input": "AKIAIOSFODNN7EXAMPLE",
      "expected": "[redacted:AWS_ACCESS_KEY_ID]",
      "actual": "[redacted:AWS_ACCESS_KEY_ID]",
      "result": "pass"
    },
    {
      "id": "C40",
      "group": "existing formats",
      "input": "eyJaaaaaaaaaa.bbbbbbbbbb.cccccccccc",
      "expected": "[redacted:JWT]",
      "actual": "[redacted:JWT]",
      "result": "pass"
    },
    {
      "id": "C41",
      "group": "existing formats",
      "input": "-----BEGIN PRIVATE KEY-----\nsynthetic only\n-----END PRIVATE KEY-----",
      "expected": "[redacted:PRIVATE_KEY]",
      "actual": "[redacted:PRIVATE_KEY]",
      "result": "pass"
    },
    {
      "id": "C42",
      "group": "existing formats",
      "input": "API_KEY=abcdef1234567890",
      "expected": "API_KEY=[redacted]",
      "actual": "API_KEY=[redacted]",
      "result": "pass"
    },
    {
      "id": "C43",
      "group": "existing formats",
      "input": "MY_SECRET: hunter2hunter2",
      "expected": "MY_SECRET=[redacted]",
      "actual": "MY_SECRET=[redacted]",
      "result": "pass"
    },
    {
      "id": "C44",
      "group": "existing formats",
      "input": "export GITHUB_TOKEN=ghp_gggggggggggggggg",
      "expected": "export GITHUB_TOKEN=[redacted:GITHUB_TOKEN]",
      "actual": "export GITHUB_TOKEN=[redacted:GITHUB_TOKEN]",
      "result": "pass"
    }
  ],
  "toolInputOutput": {
    "standalone": "tool: Bash \"[redacted:API_KEY]\" -> [redacted:API_KEY]",
    "assignment": "tool: Bash \"[redacted:API_KEY]=[redacted]\" -> [redacted:API_KEY]=[redacted]",
    "result": "pass"
  },
  "regression": {
    "baseline": "apikey_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "removedGrammar": "apikey_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "candidate": "[redacted:API_KEY]",
    "expected": "[redacted:API_KEY]"
  }
}
Evidence: Assignment leak reproduced before fix and protected afterward
[
  {
    "input": "apikey_openrouter_production=hunter2hunter2",
    "baseline": "apikey_openrouter_production=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]=hunter2hunter2",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "apikey_openrouter_production=\"hunter2hunter2\"",
    "baseline": "apikey_openrouter_production=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]=\"hunter2hunter2\"",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "apikey_openrouter_production='hunter2hunter2'",
    "baseline": "apikey_openrouter_production=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]='hunter2hunter2'",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "apikey_openrouter_production:hunter2hunter2",
    "baseline": "apikey_openrouter_production=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]:hunter2hunter2",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "apikey_openrouter_production:\"hunter2hunter2\"",
    "baseline": "apikey_openrouter_production=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]:\"hunter2hunter2\"",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "apikey_openrouter_production:'hunter2hunter2'",
    "baseline": "apikey_openrouter_production=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]:'hunter2hunter2'",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "APIKEY_OPENROUTER_PRODUCTION=hunter2hunter2",
    "baseline": "APIKEY_OPENROUTER_PRODUCTION=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]=hunter2hunter2",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "APIKEY_OPENROUTER_PRODUCTION=\"hunter2hunter2\"",
    "baseline": "APIKEY_OPENROUTER_PRODUCTION=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]=\"hunter2hunter2\"",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "APIKEY_OPENROUTER_PRODUCTION='hunter2hunter2'",
    "baseline": "APIKEY_OPENROUTER_PRODUCTION=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]='hunter2hunter2'",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "APIKEY_OPENROUTER_PRODUCTION:hunter2hunter2",
    "baseline": "APIKEY_OPENROUTER_PRODUCTION=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]:hunter2hunter2",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "APIKEY_OPENROUTER_PRODUCTION:\"hunter2hunter2\"",
    "baseline": "APIKEY_OPENROUTER_PRODUCTION=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]:\"hunter2hunter2\"",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  },
  {
    "input": "APIKEY_OPENROUTER_PRODUCTION:'hunter2hunter2'",
    "baseline": "APIKEY_OPENROUTER_PRODUCTION=[redacted]",
    "reviewedBrokenRevision": "4413883",
    "before": "[redacted:API_KEY]:'hunter2hunter2'",
    "candidate": "fc07de1cf4e96fb549fef0d1ecaf3f7615a600e1",
    "after": "[redacted:API_KEY]=[redacted]"
  }
]
Evidence: CLI invocation and prompt-checkpoint termination
Command: node bin/backpass.js analyze --harness codex --since all --analysis-agent codex --memory-file MEMORY.md --jobs 1 --json --no-ui
CWD: ~/.no-mistakes-upstream-codex/worktrees/00c42fff1637/01M619JAT2F2MH08ZZX7R87MT6/.local-test-147/repo-v2
Isolated HOME/CODEX_HOME/XDG_CONFIG_HOME; no credential environment inherited.
Stopped at completed prompt-cache checkpoint before analysis completion.
Termination: {"code":143,"signal":null}
stdout:

stderr:
· analyzing 1 transcript(s) with codex effort=medium at jobs=1
  • Evidence: Retained scratch inventory and cleanup refusal (local file: ~/.no-mistakes-upstream-codex/evidence/01M619JAT2F2MH08ZZX7R87MT6/cleanup-notes.json)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • 🚨 src/redact.js:13 - The new pattern destroys assignment names before the assignment rule at src/redact.js:26 can protect their values. For synthetic input APIKEY_OPENROUTER_PRODUCTION=hunter2hunter2, the baseline redacts the value, but this change produces [redacted:API_KEY]=hunter2hunter2. The same regression affects lowercase names, : separators, and quoted values. It reaches message text and tool input/output through src/distill.js:111,121,122, then the cached prompt and model call at src/analyze.js:313,328. Preserve assignment recognition before standalone replacement can erase its name, and add behavioral regression coverage for these forms.

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 5 of 5 scenarios driven live against the product
Scenario Result Live Evidence
Analyze standalone credentials with varied case, punctuation, newlines, and a 16-character suffix; cached prompt contains redaction markers ✅ pass live CLI-generated analysis prompt, cases C01–C09
Analyze short tokens, ordinary words, embedded prefixes, and benign token counts; cached prompt preserves them ✅ pass live CLI-generated analysis prompt, cases C10–C16
Analyze long lowercase and uppercase APIKEY assignment names using equals, colons, and quoted values; assignment secrets never survive ✅ pass live CLI-generated analysis prompt, cases C17–C32; assignment-regression.json
Analyze existing provider tokens, private keys, and ordinary secret assignments; established redaction behavior remains intact ✅ pass live CLI-generated analysis prompt, cases C33–C44
Analyze credentials and colliding assignments in tool commands and results; neither reaches the cached prompt ✅ pass live CLI-generated analysis prompt, Bash tool input and output
  • TMPDIR="$PWD/.local-test-147/tmp" node --import ./test/helpers/hermetic-config.js --test test/distill.test.js test/analyze-reuse.test.js
  • node .local-test-147/drive.mjs: executed the real CLI against isolated synthetic Codex transcripts, checked 44 cases and tool fields, and retained the generated prompt
  • Stopped the CLI at the persisted-prompt checkpoint; analysis completion and model response were outside this check
  • Executed baseline and grammar-removal redactors against synthetic credentials; both reproduced the missing-redaction regression
  • Executed revision 4413883 against assignment fixtures; reproduced the leak and confirmed the target protects the values
  • Corrected an initial fixture collision between a credential and its embedded-prefix negative control, then repeated the CLI probe successfully
  • Inventoried retained scratch and confirmed tracked files were unchanged
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@greptile-apps

greptile-apps Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Reviews (1) · Last reviewed commit: "no-mistakes(document): Document redactio..." · Reviewed by Greptile

@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate.

I reviewed the diff (no workflow, network, or exec changes) and approved fork CI. Everything is green, including no-mistakes, and the PR is CLEAN against latest main bc7bc64. It closes #147: a case-insensitive standalone apikey_ pattern with a 16-character floor, placed after the assignment pattern so a matching variable name can't expose the assigned value, with regressions that fail when the pattern is removed. Live evidence covers 5 of 5 scenarios.

VISION per-rule:

  • Evidence is the only currency: aligns (no change to quotes or the two-session bar).
  • The human owns the weights: aligns (no write-gate change).
  • Nothing the model says is taken on faith: aligns.
  • The budget is the constraint: not affected.
  • It reads what you already have and owns nothing: aligns (tightens the stated coarse redaction net without a new default block).
  • Failure is loud and named: aligns.
  • Scope: aligns.

Contract-class: restore. Redaction already promises a coarse net over obvious secret shapes on the default distill path; this adds a missing common shape, not a new surface. Merging.

@kunchenguid
kunchenguid merged commit 24f8283 into kunchenguid:main Oct 28, 2026
5 checks passed
@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate: this is merged. Thank you @WTF-Am-ID — really appreciate you taking the time on this.

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.

2 participants