Investigate CLI Prompt Injection on Trails · Entire

Does the little prompt injection work that the CLI has on trails? Investigate

Yes — at the CLI/hook layer it works.

What I found:

I verified:

Caveats:

How about in THIS repo?

For this repo/session: no, not effectively.

Findings:

Also: .opencode/plugins/entire.ts in this repo looks stale; it does not include the newer inject_context / experimental.chat.system.transform logic.

So: the code works generally, but this repo’s local hook state/cache means the trail prompt injection did not reach this current Pi session.

Dig deeper, does the preferences.json actually work?

Short answer: the preferences file works as a local gate, but the population/refresh path is weak — in this repo it is not populated even though trails are accessible.

What I verified:

But importantly:

Current session impact:

How can we make it more reliable then?

Only writing on entire enable is not enough; it should more "constantly" check based on certain events. Are the preferences.json git ignored?

Yes — preferences.json is safe from git, but the refresh model is too sparse.

Reliability improvements I’d make:

  1. Refresh on successful trail commands
    • Any successful entire trail list/show/create/update/delete/finding/watch response proves trails are enabled/accesssible.
    • So after those 2xx responses, call saveTrailsEnabledForRepo(ctx, true).
  2. Refresh on definitive disabled responses
    • On 404/403/410 from trails endpoints, save false.
    • On network errors, auth errors, 5xx: do not overwrite the cache.
  3. Add freshness metadata
    • Extend clone prefs with e.g.
      • trails_enabled_checked_at
      • trails_enabled_repo / remote key
    • Avoid stale true after origin changes or after trails are disabled.
  4. Refresh opportunistically before agent turns
    • On SessionStart, if cache is missing/stale, kick off a bounded/background refresh.
  5. Keep hook-time gate simple
    • TurnStart should only read local prefs:
      • fresh true → inject + mark decided
      • fresh false → mark decided/no inject
      • unknown/stale → request refresh, don’t mark decided

The key bug is:

missing prefs currently behaves like false and is sticky per session. Better is unknown → refresh + retry later.

All right, which are the safest triggers to make sure this isn't stale ever?

If we mean “not stale ever”, triggers alone aren’t enough. The safest model is:

  1. Validate on use
    • Before injecting, only trust a cache entry if it matches current:
      • repo key: forge/owner/repo
      • origin URL hash or canonical remote
      • API base/core/context identity
      • checked timestamp / generation
    • If it doesn’t match: treat as unknown, not false.
  2. Refresh on agent SessionStart
    • Best safe trigger for prompt injection.
  3. Refresh on every successful trail API command
    • trail list/show/create/update/delete/finding/watch
    • Any 2xx from repo-scoped trail endpoint → write trails_enabled: true.
  4. Invalidate on identity changes
    • auth login/logout/use
  5. Use a TTL
    • Even with triggers, server-side state can change without CLI knowing.

Key behavioral change:

unknown/stale must not set context_injection_decided. Current behavior makes missing prefs sticky for the whole session, which is the main bug.

Sounds good, let's make the changes.

Implemented the trail context-injection cache refresh changes.

Key changes:

Validation run:

Create a trail commit and push the changes to the new branch.

Done.

Validation run: