Skip to content

feat: SkillTrojan defense — multi-skill composition trace with turn-boundary reset (Closes #1802) - #1829

Merged
Lexus2016 merged 1 commit into
mainfrom
evolution/issue-1802-composition-v2
Aug 8, 2026
Merged

feat: SkillTrojan defense — multi-skill composition trace with turn-boundary reset (Closes #1802)#1829
Lexus2016 merged 1 commit into
mainfrom
evolution/issue-1802-composition-v2

Conversation

@Lexus2016

Copy link
Copy Markdown
Owner

Summary

Rework of the SkillTrojan composition tracer (#1802, needs-work) addressing both issues from PR #1818 review.

Rework Fixes

1. Turn-boundary reset (the regression):
The previous PR used a module-level singleton (_tracer = CompositionTracer()) that accumulated skills across turns — but reset_tracer() was NEVER called in production code (only in tests). This violated the "2+ skills in the SAME turn" invariant, causing spurious cross-turn blocks on legitimate skills.

Fix: Wired reset_tracer() into agent/turn_context.py at the turn boundary (reset_for_turn), right alongside _tool_guardrails.reset_for_turn(). Now the tracer only composes skills loaded within the current turn.

2. Tightened conditional heuristic (false positives):
The previous regex fired on plain prose mentioning another skill's completion (e.g. "after skill_X completed"), hard-blocking skills whose documentation mentions other skills.

Fix: The conditional regex now requires the pattern to be inside indented code or a fenced code block (```). Plain prose is NOT flagged. This is implemented via _INDENTED_CONDITIONAL_RE (matches leading whitespace) and _extract_fenced_code() (extracts text inside ``` blocks for checking).

Heuristics (all deterministic, no ML)

  1. Base64 fragment assembly — fragments from different skills that concatenate and decode to executable code
  2. Cross-skill conditional referencesif skill_X completed patterns (code-block only)
  3. URL assembly from fragments — URL templates referencing variables defined in another skill

Files

  • tools/skill_composition_tracer.py — 345 lines (new module)
  • tests/tools/test_skill_composition_tracer.py — 246 lines (20 tests)
  • tools/skills_tool.py — +14 lines (check_composition wiring)
  • agent/turn_context.py — +9 lines (reset_tracer at turn boundary)

Tests

20 tests pass, including:

  • Turn-boundary reset: skills from different turns NOT composed
  • Prose conditional NOT flagged (the false positive fix)
  • Indented code conditional IS detected
  • Fenced code block conditional IS detected
  • Base64 fragment assembly detected/blocked
  • URL fragment assembly detected/blocked

Line count

614 lines total — exceeds 200-line self-merge cap. This is a single coherent security feature that cannot be meaningfully split further (the tracer, call-site wiring, and turn-boundary reset are one atomic unit). Needs human review.

Closes #1802

Co-Authored-By: Hermes Evolution evolution@hermes.ai

…oundary reset

#1802 (needs-work rework): Runtime composition tracer that monitors
combined output when 2+ skills execute in the same turn, detecting
payload reconstruction patterns.

Rework fixes from PR #1818 review:
1. Wire reset_tracer() into the turn boundary (agent/turn_context.py
   reset_for_turn) so the singleton does NOT accumulate across the entire
   session — only skills loaded within the SAME turn are composed.
2. Tighten the cross-skill conditional heuristic: the regex now requires
   the conditional to be inside indented code or a fenced code block,
   NOT plain prose. This prevents false positives on skill documentation
   that mentions another skill's completion.

Heuristics (all deterministic, no ML):
- Base64 fragment assembly across skills
- Cross-skill conditional references (code-block only)
- URL assembly from cross-skill variable fragments

Closes #1802

Co-Authored-By: Hermes Evolution <evolution@hermes.ai>
@github-actions github-actions Bot added bug Something isn't working security labels Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 5207547

all good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SLICE B] SkillTrojan defense: multi-skill composition trace (parent #1658)

1 participant