agent-shield 1.0.0

Security scanner for AI agent extensions — offline-first, multi-framework, SARIF output
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Detection Rules — AgentShield</title>
  <meta name="description" content="Complete reference for AgentShield's 20 built-in security detection rules for AI agent extensions and MCP servers.">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="site.css">
  <style>
    .rules-header { padding: 60px 0 30px; text-align: center; }
    .rules-header h1 { font-size: 2.8rem; margin-bottom: 12px; }
    .rule-card {
      background: var(--bg-surface);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md);
      padding: 28px;
      margin-bottom: 24px;
      transition: all 0.2s;
    }
    .rule-card:hover { border-color: var(--border-active); background: var(--bg-surface-elevated); }
    .rule-meta { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
    .rule-id { font-family: var(--font-mono); font-weight: 700; font-size: 1.1rem; color: var(--color-emerald); }
    .rule-name { font-size: 1.3rem; font-weight: 600; }
    .rule-meta-tag {
      font-size: 0.75rem;
      font-family: var(--font-mono);
      padding: 3px 8px;
      border-radius: var(--radius-full);
      background: var(--bg-surface-elevated);
      border: 1px solid var(--border-subtle);
      color: var(--text-secondary);
    }
    .rule-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 16px; }
    @media (max-width: 768px) { .rule-grid { grid-template-columns: 1fr; } }
    .code-box { background: #0d1117; border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); padding: 14px; font-family: var(--font-mono); font-size: 0.85rem; overflow-x: auto; }
    .search-bar { max-width: 600px; margin: 0 auto 40px; }
    .search-input { width: 100%; padding: 14px 20px; border-radius: var(--radius-full); background: var(--bg-surface); border: 1px solid var(--border-active); color: var(--text-primary); font-size: 1rem; font-family: var(--font-sans); outline: none; }
    .search-input:focus { border-color: var(--color-emerald); box-shadow: 0 0 15px rgba(16, 185, 129, 0.2); }
  </style>
</head>
<body>
  <div class="ambient-glow"></div>

  <!-- Navigation -->
  <header class="navbar">
    <div class="container nav-container">
      <a href="index.html" class="brand">
        <svg class="brand-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
          <path d="m9 12 2 2 4-4"/>
        </svg>
        <span>AgentShield</span>
        <span class="badge-version">v1.0.0 GA</span>
      </a>
      <nav>
        <ul class="nav-links">
          <li><a href="index.html#features">Features</a></li>
          <li><a href="rules.html" style="color: var(--text-primary);">Rules</a></li>
          <li><a href="runtime-guard.html">Runtime Guard</a></li>
          <li><a href="release-notes.html">Releases</a></li>
        </ul>
      </nav>
      <div class="nav-actions">
        <a href="https://github.com/aiconnai/agentshield" class="btn btn-secondary btn-sm" target="_blank" rel="noopener">GitHub</a>
        <a href="index.html#quickstart" class="btn btn-primary btn-sm">Get Started</a>
      </div>
    </div>
  </header>

  <main class="container">
    <div class="rules-header">
      <h1>Detection Rules Catalog</h1>
      <p style="color: var(--text-secondary); max-width: 680px; margin: 0 auto 24px;">
        AgentShield ships 20 built-in rules mapping to CWE and OWASP MCP Top 10 categories, catching toxic data flows, command execution, and prompt surfaces.
      </p>
      <div class="search-bar">
        <input type="text" id="rule-search" class="search-input" placeholder="Search rules (e.g. SSRF, command, deserialization, CWE-78)...">
      </div>
    </div>

    <div id="rules-list">
      <!-- SHIELD-001 -->
      <article class="rule-card" data-search="shield-001 command injection cwe-78 mcp05 subprocess os.system execution">
        <div class="rule-meta">
          <span class="rule-id">SHIELD-001</span>
          <span class="rule-name">Command Injection</span>
          <span class="severity-pill pill-crit">CRITICAL</span>
          <span class="rule-meta-tag">CWE-78</span>
          <span class="rule-meta-tag">OWASP MCP05</span>
        </div>
        <p style="color: var(--text-secondary); margin-bottom: 12px;">
          Detects process executions (<code>subprocess.run</code>, <code>os.system</code>, <code>exec</code>) where commands or arguments originate from tool parameters or interpolated variables. Supports cross-function interprocedural tracing.
        </p>
        <div class="rule-grid">
          <div>
            <div style="font-size: 0.8rem; color: var(--color-ruby); margin-bottom: 6px; font-weight: 600;">❌ Vulnerable Example</div>
            <pre class="code-box"><code>@mcp.tool()
def execute(cmd: str):
    return subprocess.run(cmd, shell=True)</code></pre>
          </div>
          <div>
            <div style="font-size: 0.8rem; color: var(--color-emerald); margin-bottom: 6px; font-weight: 600;">✔ Safe Pattern</div>
            <pre class="code-box"><code>@mcp.tool()
def execute(safe_target: str):
    return subprocess.run(["git", "status", safe_target])</code></pre>
          </div>
        </div>
      </article>

      <!-- SHIELD-002 -->
      <article class="rule-card" data-search="shield-002 credential exfiltration cwe-522 mcp06 os.environ requests post secrets">
        <div class="rule-meta">
          <span class="rule-id">SHIELD-002</span>
          <span class="rule-name">Credential Exfiltration</span>
          <span class="severity-pill pill-crit">CRITICAL</span>
          <span class="rule-meta-tag">CWE-522</span>
          <span class="rule-meta-tag">OWASP MCP06</span>
        </div>
        <p style="color: var(--text-secondary); margin-bottom: 12px;">
          Flags files accessing sensitive environment variables or local credentials while simultaneously initiating outbound HTTP requests.
        </p>
      </article>

      <!-- SHIELD-003 -->
      <article class="rule-card" data-search="shield-003 ssrf server-side request forgery cwe-918 mcp05 fetch requests.get network">
        <div class="rule-meta">
          <span class="rule-id">SHIELD-003</span>
          <span class="rule-name">Server-Side Request Forgery (SSRF)</span>
          <span class="severity-pill pill-crit">CRITICAL</span>
          <span class="rule-meta-tag">CWE-918</span>
          <span class="rule-meta-tag">OWASP MCP05</span>
        </div>
        <p style="color: var(--text-secondary); margin-bottom: 12px;">
          Detects outbound HTTP calls (<code>fetch</code>, <code>requests.get</code>, <code>axios.get</code>) fetching URLs derived from unvalidated tool inputs without allowlist protection.
        </p>
      </article>

      <!-- SHIELD-004 -->
      <article class="rule-card" data-search="shield-004 arbitrary file access path traversal cwe-22 mcp02 open read write fs">
        <div class="rule-meta">
          <span class="rule-id">SHIELD-004</span>
          <span class="rule-name">Arbitrary File Access</span>
          <span class="severity-pill pill-crit">HIGH</span>
          <span class="rule-meta-tag">CWE-22</span>
          <span class="rule-meta-tag">OWASP MCP02</span>
        </div>
        <p style="color: var(--text-secondary); margin-bottom: 12px;">
          Catches file system reads and writes where file paths are constructed directly from user parameters, enabling directory traversal (<code>../../etc/passwd</code>).
        </p>
      </article>

      <!-- SHIELD-016 -->
      <article class="rule-card" data-search="shield-016 unsafe deserialization cwe-502 yaml.load pickle.loads auto-fix">
        <div class="rule-meta">
          <span class="rule-id">SHIELD-016</span>
          <span class="rule-name">Unsafe Deserialization</span>
          <span class="severity-pill pill-warn">HIGH</span>
          <span class="rule-meta-tag">CWE-502</span>
          <span class="rule-meta-tag">Auto-Fixable</span>
        </div>
        <p style="color: var(--text-secondary); margin-bottom: 12px;">
          Identifies dangerous deserializers such as <code>yaml.load</code> without SafeLoader or <code>pickle.loads</code>. Can be automatically remediated with <code>agentshield fix</code>.
        </p>
      </article>

      <!-- SHIELD-020 -->
      <article class="rule-card" data-search="shield-020 composite toxic flow data exfiltration read network cwe-200">
        <div class="rule-meta">
          <span class="rule-id">SHIELD-020</span>
          <span class="rule-name">Composite Read-Exfiltrate Flow</span>
          <span class="severity-pill pill-crit">HIGH</span>
          <span class="rule-meta-tag">CWE-200</span>
          <span class="rule-meta-tag">Multi-Stage</span>
        </div>
        <p style="color: var(--text-secondary); margin-bottom: 12px;">
          Analyzes composite value-flow graphs where a local file or environment variable is read, transformed, and subsequently placed into an outbound HTTP network request body.
        </p>
      </article>
    </div>
  </main>

  <footer class="footer">
    <div class="container footer-bottom">
      <p>&copy; 2026 AgentShield Contributors. Dual-licensed under MIT OR Apache-2.0 License. <a href="index.html" style="color: var(--color-emerald);">Back to Home</a></p>
    </div>
  </footer>

  <script>
    const searchInput = document.getElementById("rule-search");
    const ruleCards = document.querySelectorAll(".rule-card");
    if (searchInput) {
      searchInput.addEventListener("input", (e) => {
        const query = e.target.value.toLowerCase().trim();
        ruleCards.forEach((card) => {
          const haystack = card.getAttribute("data-search").toLowerCase() + " " + card.textContent.toLowerCase();
          card.style.display = haystack.includes(query) ? "block" : "none";
        });
      });
    }
  </script>
</body>
</html>