Skip to content

fix(ai): gate privileged add_finding types at the guardrail (M7)#1260

Merged
ocervell merged 1 commit into
ai-resiliencyfrom
fix/guardrail-finding-query-perms
Jul 1, 2026
Merged

fix(ai): gate privileged add_finding types at the guardrail (M7)#1260
ocervell merged 1 commit into
ai-resiliencyfrom
fix/guardrail-finding-query-perms

Conversation

@ocervell

@ocervell ocervell commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

M7 (P1, Security): `add_finding`/`query` unconditionally allowed

Finding: Injected/scanned content can drive the AI to write a `_type:"target"` finding that auto-approve later trusts, silently widening scope with no prompt.

Root cause: `secator/ai/guardrails.py:826-827` blanket-allowed `add_finding` (alongside `query`/`follow_up`):
```python
elif action_type in ("query", "follow_up", "add_finding"):
return PermissionResult(decision="allow", reason=f"{action_type} is always allowed")
```

What "privileged/trusted" means downstream: `secator/tasks/ai.py:538-556` `_auto_approve_workspace_targets()` runs `QueryEngine.search({"_type": "target"}, limit=1000)` and passes every hit to `permission_engine.add_runtime_allow([...])`. So any `target`-typed finding in the workspace is auto-approved as in-scope on the next turn. An injected `add_finding` of that type therefore smuggles a new trusted target and widens scope.

Fix

Small guardrail-layer defense (defense-in-depth). New module-level predicate:
```python
_PRIVILEGED_FINDING_TYPES = frozenset({"target"})

def _is_privileged_finding_type(action: Dict) -> bool:
return str(action.get("_type", "")).strip().lower() in _PRIVILEGED_FINDING_TYPES
```
The decision branch now returns `ask` (engine vocabulary, reuses `PermissionResult`) when an `add_finding` would mint a privileged/trusted type. It reads `_type` straight off the action dict the engine already receives — no `actions.py` change needed. Benign/info `add_finding` stays `allow`; read-only `query` and engine-internal `follow_up` are untouched.

Tests

  • New (proven, no shfmt needed): `test_add_finding_target_type_not_allowed` (→ ask), `test_add_finding_target_type_case_insensitive` (→ ask), `test_add_finding_benign_allowed` (vulnerability → allow); existing `query`/`follow_up` allow tests still pass.
  • Baseline vs after: `57 failed, 91 passed` → `57 failed, 94 passed`. The 57 failures are pre-existing and byte-identical before/after (environmental `shfmt`/`safecmd`-gated `TestEdgeCases` shell-parsing tests) — not regressions. AST parse OK.

Related trust smell (flagged, not fixed here — cross-lane)

`secator/tasks/ai.py:538-556` is the sink that auto-trusts `_type:"target"` findings. Note `_handle_add_finding` (`secator/ai/actions.py:466-467`) strips `_type` from `finding_data` and `type_map` only covers `FINDING_TYPES` (no `Target`), so today it can't build a literal Target — but this guardrail closes the intent path as defense-in-depth. AI-origin findings also aren't tagged distinctly from tool-discovered ones (`actions.py:519-524`), so downstream can't tell them apart.

🤖 Generated with Claude Code

…ndings (M7)

Injected/scanned content can drive the AI to emit an add_finding action with
_type:"target". Downstream, tasks/ai.py _auto_approve_workspace_targets() searches
_type:"target" findings and auto-approves them all as in-scope, so a smuggled
target finding silently widens scope with no prompt.

Gate at the guardrail: add_finding of a privileged (downstream-trusted) finding
type now returns "ask" instead of unconditional allow. Benign/info add_finding and
read-only query/follow_up are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2e70891d-7150-4627-9d81-dfbd45fa8209

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/guardrail-finding-query-perms

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ocervell ocervell merged commit e33c46b into ai-resiliency Jul 1, 2026
1 check passed
@ocervell ocervell deleted the fix/guardrail-finding-query-perms branch July 1, 2026 17:02
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