# Vuln vs Exploit Agent Pairs in Shannon: Understanding the Difference in Penetration Testing Pipelines

> Clarify the distinction between vuln and exploit agent pairs in Shannon. Learn how vuln agents find vulnerabilities and exploit agents attempt conditional exploitation.

- Repository: [KeygraphHQ/shannon](https://github.com/keygraphhq/shannon)
- Tags: deep-dive
- Published: 2026-02-16

---

**The `*-vuln` agent scans for vulnerabilities and writes an exploitation queue, while the `*-exploit` agent reads that queue and conditionally attempts exploitation only when `shouldExploit` returns true.**

Shannon’s penetration-testing pipeline, maintained in the **KeygraphHQ/shannon** repository, uses a dual-agent architecture where vulnerability discovery and exploitation are handled by distinct but paired agents. Understanding the difference between these **vuln and exploit agent pairs** is essential for extending the pipeline or debugging execution flow.

## What Are Vuln and Exploit Agent Pairs?

Shannon organizes its testing logic into five vulnerability classes: injection, XSS, authentication, SSRF, and authorization. For each class, the pipeline defines a **paired agent set**:

- **`*-vuln`** – The vulnerability-analysis agent
- **`*-exploit`** – The exploitation agent

These pairs operate as independent pipelines that run in parallel with other pairs, but sequentially within their own pair.

### The Vulnerability Analysis Agent (*-vuln)

The `*-vuln` agent serves as the **discovery phase** of the pair. According to the implementation in [`src/temporal/workflows.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/temporal/workflows.ts), this agent:

- Scans the target using reconnaissance data
- Produces a markdown deliverable containing the analysis report
- Writes an **exploitation-queue JSON file** that lists discovered issues with metadata

This agent always executes first within its pair and runs immediately after the Recon phase completes.

### The Exploitation Agent (*-exploit)

The `*-exploit` agent serves as the **execution phase** that acts on the vuln agent's findings. As defined in [`src/temporal/workflows.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/temporal/workflows.ts) and [`src/queue-validation.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/queue-validation.ts), this agent:

- Reads the exploitation queue generated by its paired `*-vuln` agent
- Checks the `shouldExploit` boolean in the `ExploitationDecision` interface
- Attempts exploitation **only if** the queue indicates exploitable findings exist
- Writes an exploit-specific deliverable upon successful execution

Unlike the vuln agent, the exploit agent runs **conditionally** and does not wait for other vulnerability agents to complete.

## Key Differences Between Vuln and Exploit Agents

The architectural separation creates distinct operational characteristics:

| Aspect | `*-vuln` Agent | `*-exploit` Agent |
|--------|----------------|-------------------|
| **Input** | Target URL and reconnaissance data | Queue JSON generated by paired `*-vuln` agent |
| **Output** | Markdown report + exploitation queue | Exploit deliverable (conditional) |
| **Execution Trigger** | Always runs after Recon phase | Runs only when `shouldExploit: true` |
| **Parallelism Model** | All vuln agents start simultaneously in parallel group | Each exploit starts immediately after its paired vuln completes; no global barrier |
| **Metric Label** | Recorded as `<type>-vuln` (e.g., `injection-vuln`) | Recorded as `<type>-exploit` (e.g., `injection-exploit`) |

## How the Pipeline Orchestrates Vuln and Exploit Pairs

The coordination logic resides in [`src/temporal/workflows.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/temporal/workflows.ts), specifically within the `runVulnExploitPipeline` helper function (lines 68-86):

```typescript
async function runVulnExploitPipeline(
  vulnType: VulnType,
  runVulnAgent: () => Promise<AgentMetrics>,
  runExploitAgent: () => Promise<AgentMetrics>
): Promise<VulnExploitPipelineResult> {
  const vulnMetrics = await runVulnAgent();               // ← vuln agent execution
  const decision = await a.checkExploitationQueue(activityInput, vulnType);
  let exploitMetrics: AgentMetrics | null = null;
  if (decision.shouldExploit) {                           // ← conditional check
    exploitMetrics = await runExploitAgent();             // ← exploit agent execution
  }
  // ...
}

```

The **decision logic** is implemented in [`src/queue-validation.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/queue-validation.ts) (lines 11-28), which validates that both the deliverable and queue file exist (symmetry rule) before returning the `ExploitationDecision`:

```typescript
export interface ExploitationDecision {
  shouldExploit: boolean;
  vulnerabilityCount: number;
  // ...
}

```

Parallel execution groups are defined in [`src/session-manager.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/session-manager.ts) (lines 104-107):

```typescript
export const getParallelGroups = () => Object.freeze({
  vuln: ['injection-vuln','xss-vuln','auth-vuln','ssrf-vuln','authz-vuln'],
  exploit: ['injection-exploit','xss-exploit','auth-exploit','ssrf-exploit','authz-exploit']
});

```

## Practical Example: Adding a New Agent Pair

To extend Shannon with a new vulnerability class (e.g., open-redirect), you must define both agents in [`src/session-manager.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/session-manager.ts) and [`src/types/agents.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/types/agents.ts):

```typescript
// src/types/agents.ts – extend the AgentName union
export type AgentName =
  | 'injection-vuln' | 'injection-exploit'
  | 'xss-vuln' | 'xss-exploit'
  | // ... existing pairs
  | 'open-redirect-vuln'
  | 'open-redirect-exploit';

// src/session-manager.ts – add agent definitions
export const AGENTS = Object.freeze({
  // ... existing agents
  'open-redirect-vuln': {
    name: 'open-redirect-vuln',
    displayName: 'Open‑Redirect vuln agent',
    prerequisites: ['recon']
  },
  'open-redirect-exploit': {
    name: 'open-redirect-exploit',
    displayName: 'Open‑Redirect exploit agent',
    prerequisites: ['open-redirect-vuln']
  },
});

// src/session-manager.ts – register in parallel groups
export const getParallelGroups = () => Object.freeze({
  vuln: [..., 'open-redirect-vuln'],
  exploit: [..., 'open-redirect-exploit']
});

```

The new pair automatically follows the **vuln → queue → conditional exploit** pattern managed by `runVulnExploitPipeline`.

## Summary

- **Vuln agents** (`*-vuln`) always run first, scanning targets and writing exploitation queues.
- **Exploit agents** (`*-exploit`) run conditionally based on `shouldExploit` decisions from [`src/queue-validation.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/queue-validation.ts).
- The architecture uses **independent pipelines** where vuln agents run in parallel groups, and exploit agents trigger immediately after their paired vuln agent completes.
- Extension requires defining both agents in [`src/session-manager.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/session-manager.ts) and registering them in `getParallelGroups`.

## Frequently Asked Questions

### Can exploit agents run without their corresponding vuln agents?

No. According to the source code in [`src/session-manager.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/session-manager.ts), every `*-exploit` agent lists its `*-vuln` counterpart as a prerequisite in the `AGENTS` configuration object. The `runVulnExploitPipeline` function in [`src/temporal/workflows.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/temporal/workflows.ts) also enforces this sequence by executing the vuln agent before checking the exploitation queue.

### How does Shannon decide whether to run an exploit agent?

The decision logic resides in [`src/queue-validation.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/queue-validation.ts). After a vuln agent completes, the `checkExploitationQueue` activity validates that both the deliverable and queue JSON file exist (the symmetry rule). It returns an `ExploitationDecision` object containing `shouldExploit: boolean` and `vulnerabilityCount: number`. The exploit agent runs only when `shouldExploit` is true.

### Are vuln and exploit agents executed sequentially or in parallel?

Vuln agents execute in parallel with each other as a group, defined in `getParallelGroups()` in [`src/session-manager.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/session-manager.ts). However, within each vulnerability class, the vuln and exploit agents run sequentially: the exploit agent starts only after its paired vuln agent finishes and the queue validation succeeds. Different exploit agents run independently and do not wait for other vuln agents to complete.

### Where are the exploitation decisions logged?

Decision metadata is captured in the `ExploitationDecision` interface defined in [`src/queue-validation.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/queue-validation.ts), which includes `shouldExploit`, `vulnerabilityCount`, and validation status. The `runVulnExploitPipeline` function in [`src/temporal/workflows.ts`](https://github.com/KeygraphHQ/shannon/blob/main/src/temporal/workflows.ts) records these metrics alongside agent execution data, storing them under the respective agent names (e.g., `injection-exploit`) in the pipeline state.