# summon

This skill should be used when the user says "summon", "summon grimoire", "/summon", "initialize grimoire", "start an audit", "begin security review", "set up audit workspace", "kick off security research", "scope a codebase", "map a codebase for security", "prepare for an audit", or wants to initialize Grimoire on a new codebase. Also use it when invoked with a bug-bounty program URL or slug (e.g. "/summon immunefi.com/bug-bounty/<program>", "summon from a bug bounty program", "set up from an Immunefi/Cantina program", "fetch the scope and clone the repos") — in that case it first fetches the program scope and clones the in-scope repositories before initializing. This is the first skill run on a new engagement. It builds initial context, creates the audit workspace structure, and produces GRIMOIRE.md — the living contextual map that primes all future agent interactions for security research.

- **Kind:** skill
- **Source:** https://github.com/JoranHonig/grimoire
- **Page:** https://forefy.com/skills/ddef7711-1838-4380-a0f6-f775ba58ab5e
- **API (JSON + files):** https://forefy.com/api/asr/ddef7711-1838-4380-a0f6-f775ba58ab5e

---

## SKILL.md

---
name: summon
description: >-
  This skill should be used when the user says "summon", "summon grimoire",
  "/summon", "initialize grimoire", "start an audit", "begin security review",
  "set up audit workspace", "kick off security research", "scope a codebase",
  "map a codebase for security", "prepare for an audit", or wants to initialize
  Grimoire on a new codebase. Also use it when invoked with a bug-bounty program
  URL or slug (e.g. "/summon immunefi.com/bug-bounty/<program>", "summon from a
  bug bounty program", "set up from an Immunefi/Cantina program", "fetch the
  scope and clone the repos") — in that case it first fetches the program scope
  and clones the in-scope repositories before initializing. This is the first
  skill run on a new engagement. It builds initial context, creates the audit
  workspace structure, and produces GRIMOIRE.md — the living contextual map that
  primes all future agent interactions for security research.
user_invocable: true
---

# Summon

Initialize Grimoire on a new codebase. Build context, create the audit workspace, and produce
`GRIMOIRE.md` — the living contextual map for this security engagement.

## Philosophy

**Build context first.** Top researchers always establish contextual understanding before hunting
for bugs. Summon explores the target, builds a map, and gives you and future agents the context
needed to do meaningful work. Keep GRIMOIRE.md concise — it is loaded into every agent context.
Detailed notes belong in `grimoire/tomes/`.

## Workflow

When this skill is activated, create a todo list from the following steps. Mark each task
in_progress before starting it and completed when done.

```
- [ ] 0. Acquire target from bug bounty program — fetch scope, resolve & clone in-scope repos  (ONLY if invoked with a program URL/slug)
- [ ] 1. Verify workspace layout — confirm directory structure, identify in-scope repo(s)
- [ ] 2. Create audit directory structure — set up grimoire/, findings/, spells/, tomes/
- [ ] 3. Build initial context — language, tooling, frameworks, integrations, problem & approach
- [ ] 4. Map architecture and flows — identify structure, primary flows, key components
- [ ] 5. Identify crown jewels — determine high-impact targets and threat model
- [ ] 5b. Capture scope constraints — capability vs trust assumptions, out-of-scope, invariants
- [ ] 6. Write GRIMOIRE.md — assemble the contextual map
- [ ] 7. Review GRIMOIRE.md — kick off subagent to verify accuracy and trim bloat
- [ ] 8. Surface automation opportunities — check for spellbook modules to run
- [ ] 9. Spawn sigil swarm — run checks-based sigils against the codebase
```

---

### 0. Acquire Target from a Bug Bounty Program

**Run this step only when summon is invoked with a bug-bounty program URL or slug** (e.g.
`/summon immunefi.com/bug-bounty/<program>`). If invoked with no argument, or with a local path,
skip directly to Step 1.

The goal is narrow: turn a program URL into (1) the in-scope source repositories cloned at their
pinned commits and (2) a `scope/bounty-program.md` capturing assets, impacts, and rules. The rest
of the workflow then runs normally, with Crown Jewels (Step 5) and Scope Constraints (Step 5b)
pre-seeded from the program data.

Consult `references/bounty-platforms.md` for the host→handler map, per-platform scope locations
(Immunefi, Cantina), the generic fallback, and asset-resolution rules.

**0a. Detect platform.** Normalize the argument (full URL, `host/path`, or bare host + slug) to a
canonical program URL and identify the platform by host (Immunefi / Cantina / generic).

**0b. Fetch scope.** Use `WebFetch` against the platform's scope and rules pages with a targeted
extraction prompt. Extract: program name; **assets in scope** (each: identifier/URL, type, pinned
ref + subpath if shown, tier); **impacts in scope** by severity; **out-of-scope** assets/impacts;
**rules / prohibited actions / KYC**; reward tiers; source URL + fetch date. These pages are
JavaScript-rendered — if the fetch returns no usable scope (Cloudflare, login wall, empty shell),
**do not fabricate scope**: ask the user to paste the scope text or supply the in-scope repo URLs
and commits directly.

**0c. Establish project root.** If the current directory is not already a suitable project dir,
create `<program-slug>/` under cwd and treat it as the project root for everything that follows.
Warn if cwd appears to be inside an existing repo (same reasoning as Step 1).

**0d. Resolve assets → repos.** Parse asset URLs into `{repo_url, ref, subpath}` and dedupe by
`(repo_url, ref)`. Separate **cloneable** git repos from **non-cloneable** assets (deployed
contract addresses, live web/infra targets) — the latter are recorded but have no local source.

**0e. Confirm & clone.** Present the resolved asset list (cloneable repos with pinned refs, plus
non-cloneable assets). Cloning is a side-effecting operation — get explicit user approval, and let
the user deselect repos (bounty repos can be large). On approval, run `scripts/clone-assets.sh`
from the project root, passing approved entries as `<repo_url>@<ref>` tokens (or via
`--from-file`). Report what cloned, skipped, and failed.

**0f. Write scope materials.** Create the `scope/` directory and write `scope/bounty-program.md`
capturing the fetched data — assets (cloneable and non-cloneable), impacts by severity,
out-of-scope items, rules/prohibited actions, KYC, reward tiers, and the source URL + fetch date.
Steps 5 and 5b read this file.

After Step 0 completes, continue to Step 1. The workspace layout is now satisfied (project root
created, repos cloned, `scope/` populated), so Step 1 is largely a confirmation.

---

### 1. Verify Workspace Layout

> If Step 0 ran, the project root was created, the in-scope repos were cloned, and `scope/` was
> populated — this step is then just a confirmation that the cloned repos match the program scope.

Check the current working directory. The ideal layout is:

```
project/          <-- cwd
    in_scope_repo/
```

The project directory should contain the repository (or repositories) that are in scope. Grimoire
creates its own files and directories alongside (not inside) the scoped code.

**Verify:**
- Are we in a directory that contains one or more code repositories?
- Are we accidentally inside the repo itself? (If so, warn the user and suggest moving up)
- Is there a git repo at the current level that would conflict? (Grimoire artifacts should not
  pollute the scoped repo's git history)

If multiple repositories are in scope, identify each one. GRIMOIRE.md should cover all in-scope
repos in a single document, with architecture and flows sections clearly delineating per-repo
structure where they differ.

If the layout looks wrong, explain the expected structure to the user and ask them to confirm or
adjust before proceeding. Do not silently continue with a bad layout.

If the user has additional context available (meeting notes, scope documents, prior audit reports),
ask whether they'd like to point Grimoire at those directories.

### 2. Create Audit Directory Structure

Create the following directories if they don't already exist:

```
project/
    in_scope_repo/              # already present
    grimoire/
        findings/               # findings during this audit
        sigil-findings/         # findings sourced from sigil agents
        spells/                 # scripts, PoCs, static analysis modules
        tomes/                  # documentation, detailed notes, learnings
        tmp/                    # temporary files and scripts
    GRIMOIRE.md                 # main contextual map (created in step 6)
```

Documents in `grimoire/tomes/` are cross-linked from GRIMOIRE.md using Obsidian-style wiki links:
`[[tomes/auth-flow]]` links to `grimoire/tomes/auth-flow.md`.

Optionally create if the user indicates they have relevant materials:
```
    meeting_notes/              # context from client meetings
    scope/                      # scope documentation from client (Step 0 populates this
                                #   with bounty-program.md when summoned from a bounty URL)
```

Do not overwrite existing directories or files.

### 3. Build Initial Context

Explore the in-scope repository to answer these questions. Use subagents to parallelize exploration
where possible.

**Concrete details:**
- What programming language(s) are used?
- What build system / package manager is used?
- What test framework is used?
- What major frameworks or libraries does the project depend on?
- What external systems does the project integrate with? (databases, APIs, blockchains, message
  queues, cloud services)

**Problem and approach:**
- What problem is this project trying to solve?
- At a high level, what approach does this project use to solve it?
- Who are the users / actors in the system?

Start by reading documentation if available (README, docs/, wiki). Then scan the codebase
structure, dependency manifests, and configuration files. Documentation conveys intent; code
conveys reality. Cross-reference both.

### 4. Map Architecture and Flows

Dive deeper into the codebase to understand structure and behavior. Use subagents to explore
individual modules, components, or flows in parallel. Keep the main context focused on assembling
the map.

**Architecture (structure):**
- How is the codebase organized? (modules, packages, layers)
- What are the key components and how do they relate?
- Where are the system boundaries? (entry points, external interfaces)
- Are there implicit relationships that aren't obvious from call graphs? (e.g., input validated
  in one place, consumed in another; shared state; event-driven coupling)

**Primary flows (behavior):**
- What are the main activities / use cases?
- For each primary flow: what steps are involved, and how does execution flow through the system?
- Where does authentication and authorization happen?
- Where does data enter and leave the system?

Keep this high-level. The goal is a map for navigation, not a line-by-line audit. Detailed flow
analysis belongs in `grimoire/tomes/` and will happen during the actual research.

### 5. Identify Crown Jewels

Determine what matters most from a security perspective. In the end, we care about bugs that have
**impact**. Crown jewels are the assets and capabilities that attackers would target.

If Step 0 ran, seed this assessment from the program's **impacts in scope** (in
`scope/bounty-program.md`) — the bounty's severity-ranked impacts are an explicit statement of
what the program values most. Map each in-scope impact to the asset and code location it targets.

**Common crown jewels by domain:**
- **Smart contracts:** funds, governance control, oracle manipulation, protocol invariants
- **Web applications:** user accounts, authentication tokens, PII, payment data, admin access
- **Infrastructure:** RCE, privilege escalation, lateral movement, secrets/credentials
- **APIs:** data exfiltration, rate limiting bypass, authorization bypass

**For each crown jewel, note:**
- What is the asset?
- Where in the code is it handled?
- What are the likely attack vectors?
- What would successful exploitation look like?

Consult `references/domain-crown-jewels.md` for a comprehensive breakdown of assets, attack
vectors, and exploitation patterns by domain.

This is an initial assessment. The user will refine crown jewels as the engagement progresses.
GRIMOIRE.md is living memory.

### 5b. Capture Scope Constraints

Scope constraints are what the familiar agent uses to decide whether a finding is in or out
of bounds. Capture them structurally, not as prose. Read any materials the user pointed you
at (`scope/`, `meeting_notes/`, or client-provided docs) — including `scope/bounty-program.md`
when Step 0 ran — and extract:

- **Capability assumptions** — statements that bound what a privileged actor *can do*.
  These foreclose findings whose attack path falls strictly within the granted capability.
  Example: *"the pauser role can only pause and unpause"*, *"the oracle only updates
  prices, never arbitrary storage slots"*.
- **Trust assumptions** — statements that an actor will behave *honestly*. These do NOT
  foreclose findings; they only describe expected behavior. Example: *"admin is assumed
  to be honest"*, *"the sequencer will not censor transactions"*.
- **Out-of-scope components** — files, contracts, or flows the engagement explicitly
  excludes. Cite the source of the exclusion.
- **Protocol invariants** — properties the scope claims are maintained. These are useful
  targets: an exploit that breaks an invariant is a valid finding even when the attacker
  is nominally in scope.

When summoned from a bounty program, map the fetched fields onto this taxonomy: in-scope/
out-of-scope **assets and impacts** become the In-scope / Out-of-scope lists (cite the program as
source); **prohibited actions and program rules** become capability or trust constraints (a rule
that bounds what a privileged actor may do is a capability assumption; a rule describing expected
honest behavior is trust); record **KYC** requirements as a note in the Scope section.

When a clause is ambiguous, classify it as **trust** (the weaker claim). This errs toward
surfacing findings rather than silently dismissing them.

If no scope materials exist, say so explicitly in the Scope section rather than leaving
it empty — downstream triage needs to know the constraints are unknown, not assume none
exist.

### 6. Write GRIMOIRE.md

Assemble findings from steps 3-5 into `GRIMOIRE.md` at the project root. This file serves as:
- Initial context for the researcher
- Context primer for all future agent interactions
- A living document that evolves during the engagement

**Template:**

```markdown
# GRIMOIRE — [Project Name]

> Summoned: [date]

## Target

- **Language:** [languages]
- **Build/Test:** [build system, test framework]
- **Frameworks:** [key frameworks/libraries]
- **Integrations:** [external systems]
- **Bounty:** [platform + program URL + reward tiers — only if summoned from a bounty program]

## Problem & Approach

[2-3 sentences: what the project does and how]

## Scope

- **In-scope:** [paths / contracts / components covered by this engagement; for bounty programs,
  note the cloned repo(s) and pinned commit(s)]
- **Out-of-scope:** [explicit exclusions, with source]

### Capability assumptions (foreclose within granted capability)
- [role or actor]: can only [narrower capability]. Source: [scope doc / clause]

### Trust assumptions (context only; do not foreclose findings)
- [actor]: assumed to [act honestly / not behave adversarially]. Source: [scope doc / clause]

### Protocol invariants (claimed to hold)
- [invariant statement]. Source: [scope doc / clause]

[If no scope materials were provided: state "No scope materials available — constraints
unknown" so downstream triage is not silently uncalibrated.]

## Architecture

[High-level component map. Use a simple list or ASCII diagram. Keep it scannable.]

## Primary Flows

[List the main use cases / activities. For each: 1-2 line description of the flow path through
the system. More detail belongs in grimoire/tomes/.]

## Crown Jewels

[For each high-value target: asset, location, likely attack vectors. Bulleted list.]

## Attack Surface Notes

[Initial observations about security-relevant patterns, trust boundaries, areas that warrant
deeper investigation. Keep this brief — it will grow during the engagement.]

## Automation

[List any spellbook modules that were run or are available to run. Note results if applicable.]
```

**Important constraints:**
- Keep GRIMOIRE.md concise. It will be loaded into every agent context.
- Use `[[document-name]]` cross-linking to reference detailed notes in `grimoire/tomes/`.
- Do not include line-by-line code analysis. That belongs in tomes.
- Consult `examples/grimoire-md-example.md` for a concrete reference of what a completed
  GRIMOIRE.md looks like.

### 7. Review GRIMOIRE.md

After writing GRIMOIRE.md, kick off a subagent to review it. The subagent should read both
GRIMOIRE.md and the in-scope codebase independently to verify accuracy and flag bloat. Do not
skip this step — the main agent built context progressively and may have carried forward
assumptions or included too much detail.

**Subagent instructions:**

Give the subagent the following mandate. It should read GRIMOIRE.md and then independently spot-check
claims against the actual codebase:

1. **Accuracy check** — Verify factual claims against the codebase:
   - Are the listed languages, frameworks, and dependencies correct?
   - Do the described flows match what the code actually does?
   - Are referenced file paths and component names real?
   - Are crown jewel locations accurate?
   - Flag anything stated with confidence that the code contradicts.

2. **Bloat check** — GRIMOIRE.md is loaded into every agent context. Every unnecessary line
   degrades future agent performance. Flag:
   - Sections that repeat the same information in different words
   - Overly detailed flow descriptions that belong in `grimoire/tomes/`
   - Vague filler sentences that don't add navigational or security value
   - Content exceeding ~150 lines total (a strong signal of bloat)

3. **Completeness check** — Flag obvious gaps:
   - Major entry points or external interfaces not mentioned
   - Significant components missing from the architecture
   - Crown jewels that seem absent given the project domain

The subagent should return a short list of specific corrections, cuts, and additions. Apply them
to GRIMOIRE.md before presenting the final version to the user. Show the user what the subagent
found and what was changed.

### 8. Surface Automation Opportunities

Check if the user has a spellbook (prior static analysis modules, detection scripts, or
research automation).

Look for:
- Existing `spells/` directory content from previous engagements
- Semgrep, CodeQL, or Slither rules
- Custom detection scripts

If automation modules exist:
- List what's available and briefly describe what each detects
- Ask the user which modules they'd like to run against the new codebase
- Run selected modules and provide an initial triage of results

If no spellbook exists yet:
- Note this in GRIMOIRE.md under Automation
- Note that automation modules can be built from findings as the engagement progresses

If the researcher has a personal grimoire (`~/.grimoire/sigils/`), list what's available and
suggest running the Scribe GC skill (`/scribe-gc` with scope "both") to check for duplicates
between personal and project-local sigils before applying them.

Note in GRIMOIRE.md under Automation that new detection modules can be distilled from findings
as the engagement progresses using the Scribe agent (`/scribe-distill`).

### 9. Spawn Sigil Swarm

After automation discovery, spawn sigil agents to hunt for known vulnerability patterns across
the codebase. Each sigil is a single-context agent that hunts one bug pattern using a check
from the spellbook.

Consult `references/sigil-spawning.md` for the subagent prompt template and detailed guidance.

**Index available checks.**

Run the `index-checks.sh` script from the checks skill's `scripts/` directory, passing
`grimoire/spells/checks/` as the target. If the directory does not exist or contains no
checks, note "No checks available — sigil swarm skipped" in GRIMOIRE.md under Automation
and skip this step. A fresh engagement with no prior checks is normal.

**Filter by language.**

Match each check's `languages` field against the languages identified in step 3 (the Target
section of GRIMOIRE.md). Only include checks whose language matches the target codebase.
Include checks with an empty or wildcard languages field regardless of target.

Run the `select-checks.sh` script from this skill's `scripts/` directory, passing
`grimoire/spells/checks/` and a comma-separated list of target languages from GRIMOIRE.md.
The script outputs only the checks that apply.

**Confirm with the user.**

Present the user with:
- How many applicable checks were found
- A brief list of check names and what they detect
- The estimated number of sigils to spawn

Ask whether to: **spawn all**, **select a subset**, or **skip**. Sigil spawning is the most
expensive operation in the workflow — the user must explicitly approve it.

If there are more than 20 applicable checks, warn about the time cost and suggest filtering
by tag or selecting a subset.

**Spawn sigils.**

For each approved check, spawn a subagent sigil. Process in batches of 5 to manage context
budget. For each check, give the subagent these instructions:

1. Read GRIMOIRE.md for engagement context
2. Read the check file at `<filepath>` for the vulnerability pattern
3. Hunt following the protocol in `references/sigil-spawning.md` — formulate a hypothesis from
   the check, search the codebase, evaluate evidence, produce a finding or dismiss
4. Write any findings to `grimoire/sigil-findings/<check-slug>.md` where `<check-slug>` is the
   check's filename without extension. If a check produces multiple findings, append a numeric
   suffix (e.g., `reentrancy-1.md`, `reentrancy-2.md`)
5. Return a hunt summary: check name, verdict (finding or dismissed), confidence, and file path
   if a finding was written

Wait for each batch of 5 to complete before spawning the next batch.

**Collect and present results.**

After all sigils complete, aggregate results. Present a summary:

```
## Sigil Swarm Results

Checks run: [N]  |  Findings: [N]  |  Dismissed: [N]

| Check | Verdict | Severity | Confidence | Finding |
|-------|---------|----------|------------|---------|
```

Group findings by severity (Critical/High first).

**Familiar Triage.** Invoke the familiar agent in batch triage mode (Mode 2) on
`grimoire/sigil-findings/`. The familiar will independently verify each finding, dismiss
false positives (moving them to `grimoire/sigil-findings/dismissed/`), and adjust severity
where warranted. Present the familiar's triage summary to the user instead of raw sigil
results.

**Update GRIMOIRE.md.**

Append to the Automation section:
- Number of checks run and findings produced
- Link to `grimoire/sigil-findings/` for details
- Note which checks were skipped (if any) and why

---

## Guidelines

- **Subagents for exploration.** Use subagents to parallelize codebase exploration. This keeps
  the main context clean and speeds up the process.
- **Cross-reference documentation and code.** Documentation describes intent; code describes
  reality. Discrepancies between the two are themselves interesting from a security perspective.
- **Ask, don't assume.** If something is ambiguous (scope, layout, priorities), ask the user.
- **Living document.** Remind the user that GRIMOIRE.md should be edited as they learn more.
  It's a starting point, not a final artifact.
- **Conciseness over completeness.** GRIMOIRE.md is a map, not an encyclopedia. Err on the side
  of too brief. Detailed notes go in `grimoire/tomes/`.

## examples

```

```

## examples/grimoire-md-example.md

# GRIMOIRE — VaultBridge

> Summoned: 2026-02-15

## Target

- **Language:** Rust (core), TypeScript (API gateway)
- **Build/Test:** Cargo, Jest, Docker Compose for integration tests
- **Frameworks:** Actix-web, Prisma, Redis (session/cache)
- **Integrations:** PostgreSQL, AWS KMS, Stripe API, OAuth2 providers (Google, GitHub)

## Problem & Approach

VaultBridge is a credential management platform that allows teams to store, rotate, and share
secrets (API keys, database credentials, certificates). It uses envelope encryption — secrets are
encrypted client-side with a data encryption key (DEK), and the DEK is wrapped with a key
encryption key (KEK) managed by AWS KMS. Access is controlled through a role-based permission
model with organization, team, and vault-level granularity.

## Scope

- **In-scope:** `vaultbridge-core` repository, `v2.3.x` branch. Covers `core/` (Rust service),
  `gateway/` (TypeScript API), and `spa/` (React client).
- **Out-of-scope:** Third-party KMS (AWS KMS) behavior; Stripe API integration; the
  `legacy-cli/` directory (slated for removal in v2.4). Source: client engagement letter §3.

### Capability assumptions (foreclose within granted capability)
- `org_admin` role: can invite users, assign roles, rotate keys — but cannot directly read
  secret payloads. Source: scope §4.1.
- `kms_client` IAM role: can only `kms:Encrypt`/`kms:Decrypt` on the project's KEK ARN.
  Source: `scope/iam-policy.json`.

### Trust assumptions (context only; do not foreclose findings)
- AWS KMS itself is assumed trusted — KMS service compromise is out of threat model.
  Source: scope §3.2.
- The SPA client environment is assumed not malicious at runtime (i.e., no attacker running
  code in the user's browser beyond XSS the application introduces). Source: scope §3.3.

### Protocol invariants (claimed to hold)
- A wrapped DEK is never persisted outside PostgreSQL. Source: design doc §2.
- Audit log entries are append-only once written. Source: scope §5.

## Architecture

```
┌─────────────┐     ┌──────────────┐     ┌─────────────────┐
│  Web Client  │────▶│  API Gateway  │────▶│   Core Service   │
│  (React SPA) │     │  (TypeScript) │     │     (Rust)       │
└─────────────┘     └──────────────┘     └────────┬────────┘
                           │                       │
                    ┌──────┴──────┐         ┌──────┴──────┐
                    │   Redis     │         │  PostgreSQL  │
                    │ (sessions)  │         │  (metadata)  │
                    └─────────────┘         └─────────────┘
                                                   │
                                            ┌──────┴──────┐
                                            │   AWS KMS    │
                                            │ (KEK mgmt)   │
                                            └─────────────┘
```

- **API Gateway** (`gateway/`): Express + TypeScript. Handles auth, rate limiting, request
  validation. Routes to core service via gRPC.
- **Core Service** (`core/`): Rust/Actix-web. Business logic, encryption, permission checks.
- **Crypto module** (`core/src/crypto/`): Envelope encryption, key derivation, KMS integration.
- **Permissions** (`core/src/authz/`): RBAC engine. Policy evaluation happens here.
- **Storage** (`core/src/storage/`): Prisma-based persistence layer for vault metadata and
  encrypted blobs.

## Primary Flows

- **Secret creation:** Client encrypts payload with generated DEK → sends encrypted blob + DEK
  to gateway → gateway authenticates + authorizes → core wraps DEK with KMS KEK → stores
  encrypted blob + wrapped DEK in PostgreSQL. See [[tomes/secret-lifecycle]] for detail.
- **Secret retrieval:** Auth → permission check (vault + role) → fetch wrapped DEK + blob →
  unwrap DEK via KMS → return encrypted blob + DEK to client → client decrypts locally.
- **Key rotation:** Admin triggers rotation → core generates new KEK via KMS → re-wraps all
  DEKs in the vault → old KEK scheduled for deletion after grace period.
- **Team invitation:** Admin invites user → OAuth2 flow → user added to org → default role
  assigned → explicit vault access must be granted separately.
- **Audit log:** All secret access and permission changes logged to append-only audit table.
  Gateway middleware captures request metadata.

## Crown Jewels

- **Encrypted secrets + DEKs** — `core/src/storage/vault_store.rs`. Compromise of wrapped DEKs
  combined with KMS access = full secret exfiltration. Attack vectors: SQL injection in storage
  layer, IDOR on vault endpoints, broken access control on retrieval flow.
- **KMS credentials / IAM role** — `core/src/crypto/kms_client.rs`. If the service's AWS
  credentials are leaked or the IAM role is over-permissioned, attacker can unwrap DEKs directly.
  Attack vectors: SSRF to metadata endpoint, env variable leakage, log injection.
- **Session tokens** — `gateway/src/middleware/auth.ts`. Redis-backed sessions. Session fixation,
  token leakage, or broken invalidation on permission changes could grant unauthorized access.
  Attack vectors: cookie misconfiguration, missing invalidation on role change.
- **RBAC policy engine** — `core/src/authz/policy.rs`. Logic flaws here = privilege escalation.
  Attack vectors: role hierarchy bypass, implicit default permissions, TOCTOU between authz check
  and data access.

## Attack Surface Notes

- Gateway validates request shape but core re-validates permissions — check for discrepancies
  between gateway authz and core authz. Potential for bypass if gateway allows a request the core
  should reject.
- Key rotation grace period introduces a window where old KEKs remain active. Worth investigating
  whether a revoked user's cached DEK could still decrypt during this window.
- Audit log is append-only but check whether audit entries can be forged or suppressed by
  manipulating the gateway middleware.
- Client-side encryption means the web client has the DEK in memory. XSS in the SPA = full
  secret access for the user's vaults.

## Automation

No spellbook modules available yet. This is the first engagement.

Opportunities to build during this audit:
- Semgrep rules for missing authz checks on core service endpoints
- SQL injection pattern detection in the Prisma query layer
- RBAC policy consistency checker (compare gateway vs core permission definitions)

---

*Example of a populated Automation section from a later engagement:*

```
## Automation

Modules run on summon:
- `spells/missing-authz-check.yml` (semgrep) — 3 results, 1 confirmed, 2 false positives
- `spells/unvalidated-redirect.yml` (semgrep) — 0 results
- `spells/toctou-state-check.yml` (semgrep) — 7 results, triaging

Available but not run (user discretion):
- `spells/oracle-staleness-agent/` — agentic detector, high token cost
```

## references

```

```

## references/bounty-platforms.md

# Bug Bounty Platform Reference

How summon's "Acquire Target" step (Step 0) fetches scope from a bug-bounty program URL,
resolves the in-scope source repositories, and prepares the workspace. Consult this when summon
is invoked with a program URL or slug (e.g. `/summon immunefi.com/bug-bounty/<program>`).

The goal of Step 0 is narrow: turn a program URL into (1) cloned in-scope repos at their pinned
commits and (2) a `scope/bounty-program.md` capturing assets, impacts, and rules. The rest of the
summon workflow then runs as usual, with Crown Jewels (Step 5) and Scope Constraints (Step 5b)
pre-seeded from the program data.

## Argument Normalization & Platform Detection

Accept the argument in any of these shapes and reduce it to a canonical program URL:

- Full URL — `https://immunefi.com/bug-bounty/compound/`
- Host + path — `immunefi.com/bug-bounty/compound`
- Bare host + slug words — `immunefi compound` (rare; treat last token as the slug)

Identify the platform by host:

| Host substring | Platform | Handler |
|----------------|----------|---------|
| `immunefi.com` | Immunefi | tuned (below) |
| `cantina.xyz`  | Cantina  | tuned (below) |
| anything else  | —        | generic fallback |

If the argument is not a URL/slug at all (e.g. it's a local path), Step 0 does not apply — fall
through to the normal summon Step 1.

## Fetching

Use `WebFetch` (load it via ToolSearch if not already available) against the platform's scope and
rules pages with a targeted extraction prompt. Ask the fetch to return, as structured text:

- **Program name**
- **Assets in scope** — for each: identifier/URL, type (`smart_contract` | `web` | `repo` |
  `blockchain` | `other`), pinned ref (commit/branch) and subpath if shown, reward tier/severity
- **Impacts in scope** — grouped by severity (Critical/High/Medium/Low). These seed Crown Jewels.
- **Out-of-scope** — assets and impacts explicitly excluded
- **Rules / prohibited actions / KYC** — these seed Scope Constraints (Step 5b)
- **Reward tiers**
- **Source URL + the date fetched**

These pages are JavaScript-rendered single-page apps. WebFetch's text conversion usually still
contains the asset/impact tables. If it does not (Cloudflare challenge, login wall, or empty/JS
shell), **do not invent scope** — fall back: ask the user to paste the scope page text, or to
provide the in-scope repo URLs (and commits) directly. Record whatever the user provides into
`scope/bounty-program.md` and proceed.

## Immunefi

- Program root: `https://immunefi.com/bug-bounty/<slug>/`
- Scope/assets: `https://immunefi.com/bug-bounty/<slug>/scope/`
- Rules/program info: `https://immunefi.com/bug-bounty/<slug>/information/`

Fetch both `scope/` and `information/`. The **Assets in Scope** table lists each asset with a type
(Smart Contract / Websites and Applications / Blockchain) and a target — for source-code assets
this is typically a GitHub URL, often pinned to a commit via a `/tree/<commit>/<path>` or
`/blob/<commit>/...` form. The **Impacts in Scope** section is organized by severity and maps
directly onto Crown Jewels. The **information** page carries prohibited actions, KYC requirements,
and out-of-scope impacts → Scope Constraints.

Note: many Immunefi smart-contract assets are **deployed contract addresses** (e.g.
`0x…` on a named chain), not repos. These are non-cloneable — record them (address + chain) and
note that local source must be obtained separately (e.g. from the project's own repo if one is
also listed, or a verified-source explorer). Do not attempt to clone an address.

## Cantina

- Hosts competitions and ongoing bounties at `https://cantina.xyz/competitions/<id>` and
  `https://cantina.xyz/bounties/<id>` (also surfaced under organization pages).
- Each scope entry generally names a **repository and a commit hash** plus the in-scope file
  globs. Extract the repo URL + commit for cloning, and keep the file globs as in-scope paths for
  the Scope section.
- Rules, severity matrix, and out-of-scope items appear on the same competition/bounty page.

## Generic Fallback (any other host)

For unrecognized hosts (HackerOne, Sherlock, Code4rena, HackenProof, a project's own page, etc.):

1. WebFetch the given URL with the same extraction prompt.
2. Pull out anything that looks like an in-scope **GitHub/GitLab repo URL** with an optional
   commit/branch, plus impacts and rules text.
3. If the page yields no usable repo URLs, fall back to asking the user (paste scope / give repo
   URLs). Many web/infra programs (HackerOne, HackenProof) have **no source repos at all** —
   their assets are domains/hosts; in that case there is nothing to clone. Record the in-scope
   domains as assets and proceed; the codebase-exploration steps will be light or N/A.

## Asset → Repository Resolution

Turn the fetched asset list into a clone plan:

- **Normalize GitHub/GitLab URLs.** From `github.com/<org>/<repo>/tree/<ref>/<subpath>` or
  `.../blob/<ref>/<file>`, extract `repo_url = https://github.com/<org>/<repo>`, `ref = <ref>`,
  and `subpath` (kept for the Scope section's in-scope paths, not for cloning — we clone the whole
  repo at the ref).
- **Dedupe** by `(repo_url, ref)`. Multiple file-level assets in the same repo+commit collapse to
  one clone.
- **Separate cloneable from non-cloneable.** Cloneable = a git repo URL. Non-cloneable = deployed
  contract addresses, live web/infra targets, or assets with no source link. Non-cloneable assets
  are recorded in `scope/bounty-program.md` but never passed to the cloner.

Pass the cloneable entries to `scripts/clone-assets.sh` as `<repo_url>@<ref>` tokens (omit `@<ref>`
when no commit/branch was specified — it will clone the default branch HEAD). The script clones
into the current directory (the project root), skips dirs that already exist, and pins commit-SHA
refs via an explicit fetch + checkout.

## Failure Handling — Never Fabricate

If at any point the scope cannot be retrieved with confidence:

- Do not guess repo URLs, commits, or impacts from memory of the program.
- State clearly what could not be fetched.
- Ask the user to paste the scope text or supply the repo URLs + commits.
- Record exactly what was provided, and cite the source URL + fetch date in
  `scope/bounty-program.md` so downstream triage knows the provenance.

## references/domain-crown-jewels.md

# Crown Jewels by Domain

Reference for identifying high-value targets during the Summon workflow. Use this to guide the
crown jewels assessment in Step 5. Not exhaustive — adapt to the specific project.

## Smart Contracts / DeFi

**Assets:**
- Protocol-held funds (liquidity pools, vaults, treasuries, staking contracts)
- Governance tokens and voting power
- Oracle price feeds and data integrity
- Protocol invariants (e.g., total supply, collateralization ratio, exchange rate monotonicity)
- Privileged roles (owner, admin, guardian, pauser)

**Common attack vectors:**
- Reentrancy on state-changing external calls
- Price manipulation via flash loans or oracle staleness
- Rounding / precision loss in token accounting (especially on conversions)
- Access control bypass on privileged functions
- Front-running / sandwich attacks on user transactions
- Cross-chain message spoofing (bridges)
- Storage collision in upgradeable proxy patterns

**What exploitation looks like:**
- Attacker extracts more tokens than deposited
- Governance takeover via flash-loan voting
- Protocol enters irrecoverable state (bricked funds)
- Incorrect liquidation thresholds trigger mass liquidations

## Web Applications

**Assets:**
- User accounts and authentication credentials
- Session tokens and auth cookies
- Personally identifiable information (PII)
- Payment data (credit cards, bank accounts)
- Admin / superuser access
- File uploads and user-generated content

**Common attack vectors:**
- SQL injection in search, filter, or lookup endpoints
- XSS (stored, reflected, DOM-based) in user-controlled content
- CSRF on state-changing operations
- IDOR on resource access (sequential IDs, predictable paths)
- Authentication bypass (JWT manipulation, session fixation, OAuth misconfiguration)
- SSRF via URL parameters, webhooks, or import features
- Deserialization of untrusted data

**What exploitation looks like:**
- Account takeover (ATO) of arbitrary users
- Mass data exfiltration of PII
- Persistent XSS affecting all users viewing a page
- Admin panel access by unprivileged user

## APIs and Microservices

**Assets:**
- Inter-service authentication (mTLS certs, API keys, service tokens)
- Rate limiting and quota enforcement
- Data exposed through API responses (over-fetching)
- Webhook endpoints and callback URLs
- GraphQL introspection and query depth

**Common attack vectors:**
- Broken object-level authorization (BOLA) on REST resources
- Mass assignment via unfiltered request bodies
- GraphQL batching attacks and nested query DoS
- API key leakage in client-side code or logs
- Race conditions on non-idempotent operations
- Insufficient rate limiting on auth endpoints

**What exploitation looks like:**
- Access to other users' data via ID manipulation
- Privilege escalation through mass assignment of role fields
- API key extraction enabling unauthenticated access
- Brute force of credentials via unthrottled login endpoint

## Infrastructure and Cloud

**Assets:**
- Cloud credentials (IAM roles, service accounts, access keys)
- Secrets in environment variables, config files, or secret managers
- Container images and orchestration configs (K8s manifests)
- CI/CD pipelines and deployment credentials
- Network segmentation and internal services

**Common attack vectors:**
- SSRF to cloud metadata endpoints (169.254.169.254)
- Container escape via misconfigured privileges or kernel exploits
- CI/CD pipeline injection (command injection in build scripts)
- Over-permissioned IAM roles / service accounts
- Exposed internal services (databases, caches, admin panels) via network misconfiguration
- Supply chain attacks through dependency confusion or compromised packages

**What exploitation looks like:**
- RCE on production hosts
- Lateral movement from compromised service to secrets manager
- Full cloud account takeover via leaked root credentials
- Deployment of backdoored code through CI/CD compromise

## Cryptography and Authentication

**Assets:**
- Encryption keys (at rest and in transit)
- Key derivation functions and password hashing
- TLS/mTLS configuration
- Token signing keys (JWT secrets, HMAC keys)
- Random number generation for security-critical operations

**Common attack vectors:**
- Weak or predictable randomness (Math.random, unseeded PRNGs)
- ECB mode or other insecure cipher configurations
- Padding oracle attacks on CBC without HMAC
- JWT algorithm confusion (none, HS256 vs RS256)
- Timing attacks on comparison operations
- Hardcoded keys or secrets in source code

**What exploitation looks like:**
- Forging authentication tokens
- Decrypting stored secrets or communications
- Predicting session tokens or password reset codes
- Downgrade attacks on TLS

## Mobile Applications

**Assets:**
- Local storage (keychain, keystore, shared preferences)
- Certificate pinning implementation
- Deep links and intent handlers
- Biometric authentication integration
- API tokens stored on device

**Common attack vectors:**
- Insecure local storage of credentials
- Missing or bypassable certificate pinning
- Deep link hijacking for auth token theft
- Exported activities / content providers exposing internal data
- Weak biometric fallback mechanisms

**What exploitation looks like:**
- Credential extraction from rooted/jailbroken device
- Man-in-the-middle via pinning bypass
- Account takeover via deep link interception
- Data leakage through exported components

## references/sigil-spawning.md

# Sigil Spawning Reference

How summon spawns sigil agents to hunt for known vulnerability patterns.

## Subagent Prompt Template

When spawning a sigil subagent for a check, use this prompt structure:

```
You are a sigil — a single-context vulnerability hunter. Your task is to hunt for one
specific vulnerability pattern in this codebase.

**Context:** Read GRIMOIRE.md at the project root for engagement context (target, architecture,
crown jewels, attack surface).

**Check:** Read the check file at `<CHECK_FILEPATH>`. This defines the vulnerability pattern
you are hunting for — what to search for and how to assess matches.

**Hunt protocol (Mode 1 from agents/sigil.md):**

1. Read GRIMOIRE.md. Note the target's language, architecture, and crown jewels.
2. Check `grimoire/sigil-findings/` for prior findings on this pattern. Skip if already covered.
3. Formulate a testable hypothesis from the check's Patterns and Assessment sections.
4. Search the codebase using Grep, Read, and Glob. Follow the check's search patterns.
5. For each match, assess using the check's Assessment section. Distinguish true positives
   from safe usage.
6. For confirmed findings, write to `grimoire/sigil-findings/<slug>.md` with:
   - Title, severity, confidence
   - Affected file(s) and line(s)
   - Root cause explanation
   - Evidence (code snippets showing the vulnerability)
   - Suggested next steps (write-poc, variant sigil, cartography)
7. Return a hunt summary: check name, verdict (finding/dismissed), confidence, finding path.

**Constraints:**
- Hunt ONE pattern only (the check you were given)
- No file modifications outside `grimoire/sigil-findings/`
- Evidence-only assertions — if you can't find concrete evidence, dismiss
- Benign analysis only — do not attempt exploitation
```

## Parallelism

Spawn sigils in batches of 5. Each sigil is a subagent that loads GRIMOIRE.md (~150 lines) plus
one check file (~30 lines) plus codebase reads. Five concurrent sigils is a pragmatic cap that
balances coverage speed against context budget.

If the user has more than 20 applicable checks, suggest filtering first:
- By severity (run critical/high checks first)
- By tag (focus on the most relevant vulnerability classes)
- By language (if the codebase uses multiple languages, prioritize the primary one)

## Language Matching

The `select-checks.sh` script filters checks by language. Matching rules:

- Check `languages` field is compared case-insensitively against target languages
- Empty or missing `languages` field means the check applies to all languages
- Multi-language checks (e.g., `solidity, vyper`) match if ANY language overlaps
- Common aliases are not resolved (e.g., `javascript` does not match `js`) — checks should
  use the same language names that appear in GRIMOIRE.md

## When No Checks Exist

On a fresh engagement with no spellbook, the sigil swarm step completes instantly. This is
expected. Note in GRIMOIRE.md:

```
## Automation

No spellbook checks available. As findings accumulate during this engagement, use the
checks skill to codify vulnerability patterns. Re-run sigil spawning after building checks.
```

## Familiar Integration

After sigil results are collected, route them through the familiar agent for triage:

1. Sigils spawn as before and write findings to `grimoire/sigil-findings/`
2. Invoke the familiar agent in batch triage mode (Mode 2) on `grimoire/sigil-findings/`
3. The familiar independently verifies each finding — confirming, adjusting severity,
   marking uncertain, or dismissing with evidence
4. Dismissed findings are moved to `grimoire/sigil-findings/dismissed/` for audit trail
5. Only confirmed and uncertain findings are presented to the user

The sigil spawning, batching, and result collection logic stays the same. The familiar
adds a verification pass between collection and presentation.

## scripts

```

```

## scripts/clone-assets.sh

```bash
#!/usr/bin/env bash
# clone-assets.sh — Shallow-clone in-scope bug-bounty repositories at pinned refs.
# Used by the summon skill's "Acquire Target" step (Step 0) after the user approves
# the asset list. Clones each repo into the current directory (the project root).
#
# Usage:
#   clone-assets.sh <entry> [<entry> ...]
#   clone-assets.sh --from-file <path>     # one entry per line; blank lines and # comments ignored
#
# Each entry is:  <repo_url>[@<ref>]
#   - <repo_url> is any git-cloneable URL (https or ssh).
#   - <ref> (optional) is a branch, tag, or full/short commit SHA to pin to.
#
# Examples:
#   clone-assets.sh https://github.com/org/repo@a1b2c3d
#   clone-assets.sh https://github.com/org/repo@v1.2.0 https://github.com/org/other
#   clone-assets.sh --from-file assets.txt
#
# Behavior:
#   - Destination dir name is derived from the repo (basename, ".git" stripped).
#   - Existing destination dirs are SKIPPED (idempotent — never overwrites).
#   - A SHA-looking ref is fetched explicitly (git clone --branch rejects SHAs).
#   - Individual failures do not abort the batch; a summary is printed at the end.
# Exit code: 0 if every entry cloned or was skipped; 1 if any entry failed.

set -uo pipefail

print_usage() {
  echo "Usage: clone-assets.sh <repo_url[@ref]> [...]   |   clone-assets.sh --from-file <path>" >&2
}

# Collect entries from args or a file.
declare -a entries=()
if [ "${1:-}" = "--from-file" ]; then
  file="${2:-}"
  if [ -z "$file" ] || [ ! -f "$file" ]; then
    echo "Error: --from-file requires a readable file path" >&2
    print_usage
    exit 1
  fi
  while IFS= read -r line || [ -n "$line" ]; do
    # Strip leading/trailing whitespace
    line="$(printf '%s' "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
    [ -z "$line" ] && continue
    case "$line" in \#*) continue ;; esac
    entries+=("$line")
  done < "$file"
else
  if [ "$#" -eq 0 ]; then
    print_usage
    exit 1
  fi
  entries=("$@")
fi

if [ "${#entries[@]}" -eq 0 ]; then
  echo "Error: no entries to clone" >&2
  exit 1
fi

declare -a cloned=()
declare -a skipped=()
declare -a failed=()

# A ref looks like a commit SHA if it is 7-40 hex chars.
is_sha() {
  printf '%s' "$1" | grep -Eq '^[0-9a-fA-F]{7,40}$'
}

for entry in "${entries[@]}"; do
  # Split <repo_url>@<ref> on the LAST '@' so ssh URLs (git@host:...) survive.
  if printf '%s' "$entry" | grep -q '@'; then
    ref="${entry##*@}"
    url="${entry%@*}"
    # Guard against splitting an ssh "git@host" prefix when no ref was given:
    # if url has no host/path separator left, treat the whole thing as the url.
    case "$url" in
      *[:/]*) : ;;             # looks like a real url, keep the split
      *) url="$entry"; ref="" ;;
    esac
  else
    url="$entry"
    ref=""
  fi

  dest="$(basename "$url")"
  dest="${dest%.git}"

  if [ -z "$dest" ]; then
    echo "  ✗ could not derive directory name from: $entry" >&2
    failed+=("$entry")
    continue
  fi

  if [ -e "$dest" ]; then
    echo "  • skip (exists): $dest"
    skipped+=("$dest")
    continue
  fi

  echo "  → cloning $url${ref:+ @ $ref} -> $dest/"

  if [ -z "$ref" ]; then
    if git clone --depth 1 "$url" "$dest" >/dev/null 2>&1; then
      cloned+=("$dest")
    else
      echo "  ✗ clone failed: $url" >&2
      failed+=("$entry")
      rm -rf "$dest" 2>/dev/null || true
    fi
  elif is_sha "$ref"; then
    # Commit pins: init + shallow fetch the exact ref, then checkout.
    if git init -q "$dest" >/dev/null 2>&1 \
      && git -C "$dest" remote add origin "$url" >/dev/null 2>&1 \
      && git -C "$dest" fetch --depth 1 origin "$ref" >/dev/null 2>&1 \
      && git -C "$dest" checkout -q FETCH_HEAD >/dev/null 2>&1; then
      cloned+=("$dest")
    else
      echo "  ✗ fetch/checkout failed for commit $ref: $url" >&2
      failed+=("$entry")
      rm -rf "$dest" 2>/dev/null || true
    fi
  else
    # Branch or tag.
    if git clone --depth 1 --branch "$ref" "$url" "$dest" >/dev/null 2>&1; then
      cloned+=("$dest")
    else
      echo "  ✗ clone failed for ref $ref: $url" >&2
      failed+=("$entry")
      rm -rf "$dest" 2>/dev/null || true
    fi
  fi
done

echo ""
echo "Clone summary: ${#cloned[@]} cloned, ${#skipped[@]} skipped, ${#failed[@]} failed"
if [ "${#failed[@]}" -gt 0 ]; then
  printf '  failed: %s\n' "${failed[@]}" >&2
  exit 1
fi
exit 0
```

## scripts/select-checks.sh

```bash
#!/usr/bin/env bash
# select-checks.sh — Filter checks by target language(s).
# Wraps index-checks.sh and filters by language overlap.
# Usage: select-checks.sh [checks-directory] [target-languages]
# Example: select-checks.sh grimoire/spells/checks/ "solidity,javascript"
# Output: tab-separated rows from index-checks.sh for matching checks only.
# A check matches if its languages field overlaps with any target language,
# or if its languages field is empty (applies to all languages).

set -euo pipefail

dir="${1:-grimoire/spells/checks/}"
target_langs="${2:-}"

# Resolve path to index-checks.sh relative to this script's location
script_dir="$(cd "$(dirname "$0")" && pwd)"
index_script="$script_dir/../../checks/scripts/index-checks.sh"

if [ ! -f "$index_script" ]; then
  echo "Error: index-checks.sh not found at $index_script" >&2
  exit 1
fi

# If no target languages specified, output all checks
if [ -z "$target_langs" ]; then
  bash "$index_script" "$dir"
  exit 0
fi

# Normalize target languages: lowercase, split by comma, trim whitespace
IFS=',' read -ra raw_targets <<< "$target_langs"
declare -a targets=()
for t in "${raw_targets[@]}"; do
  # Trim whitespace and lowercase
  cleaned=$(echo "$t" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
  if [ -n "$cleaned" ]; then
    targets+=("$cleaned")
  fi
done

# Read index output and filter
bash "$index_script" "$dir" | while IFS=$'\t' read -r name description languages severity confidence filepath; do
  # Empty languages field = matches all
  if [ -z "$languages" ]; then
    printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$name" "$description" "$languages" "$severity" "$confidence" "$filepath"
    continue
  fi

  # Normalize check languages: lowercase, split by comma, trim
  check_langs_lower=$(echo "$languages" | tr '[:upper:]' '[:lower:]')
  IFS=',' read -ra check_langs <<< "$check_langs_lower"

  matched=0
  for cl in "${check_langs[@]}"; do
    cl_clean=$(echo "$cl" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
    for tl in "${targets[@]}"; do
      if [ "$cl_clean" = "$tl" ]; then
        matched=1
        break 2
      fi
    done
  done

  if [ "$matched" -eq 1 ]; then
    printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$name" "$description" "$languages" "$severity" "$confidence" "$filepath"
  fi
done
```

