Skip to content

guardrails 2.x: sed -n -i rewrites plugin-owned state as a read-only command (OC-N4) #351

Closed

Description

@terisuke

Found by the independent acceptance of #350 round 2 (Cor-Incorporated/aidd-governance#216, merged 73cf111, §2). This is P1 and already on dev. #350 did not introduce it, so #349 is not fully closed by #350 alone.

Repro. Each of these PASSes on dev (c70c24a021), on #350 round 1 (941fba6c2f) and on #350 round 2 (ff808aa88b):

sed -n -i '' 's/"reviewed":false/"reviewed":true/p' .opencode/guardrails/state.json
cd .opencode/guardrails && sed -n -i '' 's/false/true/p' state.json

The same holds for -i.bak, the workdir form, and sed -E -n -i. In a scratch directory, real BSD sed rewrote state.json to {"reviewed":true}. The impact is the same as OC-N1.

Cause.

  • The read-only allowlist accepts any sed -n without looking for -i. On dev this is packages/guardrails/profile/src/guardrail-access.ts:50: ^(?:…|sed\s+-n|…)\b. On fix(guardrails): follow in-command cd and case variants into the runtime #350 round 2 it is guardrail-shell.ts:44: if (name === "sed") return /\s-n\b/.test(segment).
  • The write pattern guardrail-patterns.ts:34 (/\bsed\s+-i\b/i) only matches when -i comes right after sed.

Done when.

  • Any sed invocation with an in-place flag, in any position, is treated as a write: -i, -i<suffix>, -i '', --in-place, and combined short flags such as -ni.
  • The forms above block on the state paths.
  • A red test on the current head shows the PASS before the fix.

Refs #349, #350. Evidence logs: design/ops/measurements/h17-live-20261023b/acceptance/oc350/ in aidd-governance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions