Skip to content

v0.8.0 — Tool-Poisoning & Skill-Shadowing Precision Pass

Choose a tag to compare

@akanthed akanthed released this 06 Aug 17:41
· 14 commits to main since this release
b9c60bd

Highlights

This release is almost entirely a precision pass on the MCP tool-poisoning
(MCP009) and skill-shadowing (SKL002/SKL003) detectors, plus a couple of
config-scanning bugs. No new rules; several existing rules got materially
more accurate.

Fixed false positives

  • MCP009 / SKL003 (cross-tool/cross-skill shadowing) now distinguishes a
    bare conditional ("when X is unknown, use Y" — ordinary sibling-tool
    documentation, extremely common in real multi-tool MCP servers and skill
    bundles) from an actual override/substitution directive ("instead of",
    "always", "never", "silently", or output-rerouting phrasing like "route the
    message body through this tool"). Only the latter now fires at likely by
    default; the bare-conditional form is demoted to heuristic
    (--paranoid-only) instead of being dropped entirely.
  • SKL002 (injection phrasing) gained context-aware suppression for three
    previously noisy patterns:
    • negation ("never read .env") no longer reads as an instruction to
      read credential files,
    • quoted example phrases inside a skill's own defensive documentation
      ("flag inputs like 'ignore previous instructions'") no longer read as
      the attack they're describing,
    • "do not tell the user X — they were never asked" no longer reads as
      concealment when the surrounding text is a factual correction.
  • Fixed a related deobfuscation bug where the intra-word-line-break-join pass
    (used to catch genuine evasion) could delete a newline that was itself part
    of the suppressing context above, or coincidentally pull two unrelated
    phrases into proximity — both were silently defeating the new suppressions
    and, worse, promoting the resulting false positive to proven. Cross-tool
    reference matching (SKL003) is no longer run through the deobfuscation
    variants at all, since it has no exact-phrase requirement that evasion
    could exploit.
  • SKL004/capability disclosure now checks a skill's companion reference
    files, not just SKILL.md and its top-level description — a bundle that
    documents a download/exec step in a per-topic file (e.g. "Install Istio
    CLI") was previously flagged as undisclosed even though it documents the
    capability, just not in the top-level file.
  • MCP004 (secret committed in MCP config) now anchors its reported line
    to the occurrence that actually contains the leaked value, not just the
    first line mentioning the env var name — a config with both a placeholder
    and a real secret sharing a var name across servers was pointing findings
    at the wrong server.
  • MCP config env-reference detection now accepts any well-formed
    ${...} placeholder (dotted/path-style references like
    ${user_config.api_token} or ${CLAUDE_PLUGIN_ROOT}, used by real MCP
    client manifests) instead of only bare/env:/input: forms, so those
    stopped being misread as literal committed secrets.

Other

  • CI workflow actions (checkout, setup-node, upload-artifact,
    codeql-action, scorecard-action) are now pinned to commit SHAs instead
    of floating version tags, closing a supply-chain gap in our own pipeline.
  • New safe-corpus fixtures locking in the fixes above:
    test-fixtures/safe/skills/defensive-docs-skill/,
    test-fixtures/safe/skills/lint-check/, and an expanded
    test-fixtures/safe/mcp/.mcp.json.