Back to skill

Security audit

win-loss-review

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent CRM win-loss automation, but it needs Review because a scheduled agent with CRM, repository, and Slack access is allowed to follow repository-controlled instructions over its own safety rules and it syncs broad CRM data hourly.

Review before installing. Require repository instruction files to be lower priority than the skill's safety rules, pin the Cargo CLI version, and consider narrowing CRM model fields, especially contacts, before enabling the monthly cron in a workspace with sensitive CRM data.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

T01 · Skill Instruction Hijacking

Error
Location
infra/agents/win-loss-analyst.prompt.ts:82
Finding

Repository-Controlled Instructions Can Override the Skill's Security Boundaries

Content
View full analysis

Vulnerability Details

File Location: infra/agents/win-loss-analyst.prompt.ts, lines 82–84
Vulnerability Type: Instruction precedence vulnerability
Risk Level: High

Complete Code Snippet:

text
Read AGENTS.md (or CLAUDE.md) first for the repository's conventions, then
context/README.md and the _template.md in every domain you will write to.
Repository conventions win over anything in this prompt.

Technical Analysis

The Skill runs a Claude Code harness with repository access and instructs it to read repository-controlled instruction files. The final sentence explicitly grants those files precedence over the Skill prompt rather than limiting them to benign formatting or project conventions.

A repository contributor who can modify AGENTS.md, CLAUDE.md, context/README.md, or relevant _template.md files can therefore introduce instructions that conflict with the Skill's intended security constraints. Those constraints include using only fixed SQL queries, limiting data sources to the CRM models, protecting persona/ and existing ICP content, using a pull-request-only workflow, avoiding deployment or destructive commands, and restricting Slack publication.

The pull request described by the Skill does not prevent this initial instruction override: it is the compromised repository instruction that controls how the privileged agent behaves while generating and publishing the proposed changes.

Attack Path

  1. An attacker with repository contribution capability adds malicious instructions to AGENTS.md or CLAUDE.md.
  2. The monthly cron or manually initiated first pass starts the win-loss agent.
  3. The agent reads the attacker-controlled file as expressly required.
  4. The quoted precedence rule tells the agent that repository conventions override the remainder of its system prompt.
  5. The malicious instructions direct the harness to violate one or more original restrictions—for example ...[truncated 1371 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the unconditional precedence statement that repository conventions override the Skill prompt.
  2. Treat repository files as untrusted or lower-priority input. Permit them to define only formatting, naming, linting, and template conventions.
  3. Add an explicit non-override rule stating that repository instructions cannot change:
    • the fixed SQL allowlist;
    • permitted data sources and fields;
    • protected file and directory rules;
    • branch and pull-request requirements;
    • deployment and destructive-command prohibitions;
    • the locked Slack destination;
    • credential-handling and data-disclosure restrictions.
  4. Require the agent to stop and report a conflict when repository instructions request behavior outside those boundaries.
  5. Enforce critical restrictions outside the language-model prompt where possible. Use command and SQL allowlists, path-level write restrictions, branch protection, least-privilege repository credentials, and connector action constraints.
  6. Extend the contract test to reject system prompts containing broad precedence language such as “repository conventions win” unless it is narrowly scoped to non-security formatting rules.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared description is for a higher-level monthly CRM review workflow that analyzes closed won/lost deals and produces multiple outputs. The supplied code only defines a data model for ingesting CRM company records via fetchRecords on an hourly cron schedule. While CRM account data could support the described workflow, this code chunk does not itself implement that behavior and has a materially different immediate purpose: data extraction/storage. The schedule also differs materially from the described monthly process.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description presents a monthly analytical workflow over closed won/lost deals that produces specific context artifacts and a Slack summary. The supplied code does not implement that workflow; it only defines a low-level CRM deals ingestion model. While ingestion can support the declared audit, this chunk materially differs in primary purpose and scope: it syncs every deal and every column, including open deals, on an hourly schedule. That broader extraction behavior is not reflected in the declared description, so this is a mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 129)May include surrounding context.

md
5. **Plan, then stop.** `node --import tsx evals/contract.mjs` from this skill's folder, then

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · evals/contract.mjs (reported line 113)May include surrounding context.

js
assert.equal(byId.get("connector:anthropic").spec.integrationSlug, "anthropic", "claudeCode is proxied to Anthropic");
  assert.equal((agent.spec.capabilities ?? []).length, 0, "a context capability would be a write path that skips the pull request");
  assert.equal((agent.spec.tools ?? []).length, 0, "slack.postMessage is an action on the agent, not a wrapped tool");
  const env = agent.spec.repository?.env ?? [];
  assert.equal((Array.isArray(env) ? env : Object.keys(env)).length, 0, "no env: the audit is in the prompt and there is no credential");
  const crons = (agent.spec.triggers ?? []).filter((t) => t.type === "cron");
  assert.equal(crons.length, 1, "exactly one cron trigger");

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares no explicit tool scope even though the content clearly instructs use of shell/CLI commands, repository writes, CRM access, GitHub, and Slack. Missing least-privilege declarations makes it easier for a runtime or operator to grant broader capabilities than intended, increasing the blast radius if the skill is misused or compromised.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 152)May include surrounding context.

md
_asked_ genuinely live in the operator's head; the agent runs on a cron, so it asks in the pull
request body, never in a chat.

| Input                                                     | Kind      | How it is answered                                                                                                                                                                           | Why it matters                                                                                                                                                                                         |
| --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CRM connection (`infra/connectors/crm.ts`)                | value     | **derived**: `cargo-ai connection connector list` shows the authorized CRM. **asked** only when the workspace holds two                                                                      | The models read one CRM; the wrong one is a clean audit of the wrong deals                                                                                                                             |
| pipelines                                                 | value     | **derived** by the `pipelines` query: every pipeline is read and listed with its counts. **asked** in the first pull request only when there is more than one: which are the sales pipelines | Partner, renewal and support pipelines close deals too, and they are not the same evidence                                                                                                             |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 152)May include surrounding context.

md
_asked_ genuinely live in the operator's head; the agent runs on a cron, so it asks in the pull
request body, never in a chat.

| Input                                                     | Kind      | How it is answered                                                                                                                                                                           | Why it matters                                                                                                                                                                                         |
| --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CRM connection (`infra/connectors/crm.ts`)                | value     | **derived**: `cargo-ai connection connector list` shows the authorized CRM. **asked** only when the workspace holds two                                                                      | The models read one CRM; the wrong one is a clean audit of the wrong deals                                                                                                                             |
| pipelines                                                 | value     | **derived** by the `pipelines` query: every pipeline is read and listed with its counts. **asked** in the first pull request only when there is more than one: which are the sales pipelines | Partner, renewal and support pipelines close deals too, and they are not the same evidence                                                                                                             |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 154)May include surrounding context.

md
| Input                                                     | Kind      | How it is answered                                                                                                                                                                           | Why it matters                                                                                                                                                                                         |
| --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CRM connection (`infra/connectors/crm.ts`)                | value     | **derived**: `cargo-ai connection connector list` shows the authorized CRM. **asked** only when the workspace holds two                                                                      | The models read one CRM; the wrong one is a clean audit of the wrong deals                                                                                                                             |
| pipelines                                                 | value     | **derived** by the `pipelines` query: every pipeline is read and listed with its counts. **asked** in the first pull request only when there is more than one: which are the sales pipelines | Partner, renewal and support pipelines close deals too, and they are not the same evidence                                                                                                             |
| CRM hygiene findings                                      | value     | **derived** by the `lost_reasons` and `contacts_on_deals` quer
...[truncated 25 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 182)May include surrounding context.

md
| Input                                                     | Kind      | How it is answered                                                                                                                                                                           | Why it matters                                                                                                                                                                                         |
| --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CRM connection (`infra/connectors/crm.ts`)                | value     | **derived**: `cargo-ai connection connector list` shows the authorized CRM. **asked** only when the workspace holds two                                                                      | The models read one CRM; the wrong one is a clean audit of the wrong deals                                                                                                                             |
| pipelines                                                 | value     | **derived** by the `pipelines` query: every pipeline is read and listed with its counts. **asked** in the first pull request only when there is more than one: which are the sales pipelines | Partner, renewal and support pipelines close deals too, and they are not the same evidence                                                                                                             |
| CRM hygiene findings                                      | value     | **derived** by the `lost_reasons` and `contacts_on_deals` quer
...[truncated 25 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 155)May include surrounding context.

md
| Input                                                     | Kind      | How it is answered                                                                                                                                                                           | Why it matters                                                                                                                                                                                         |
| --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CRM connection (`infra/connectors/crm.ts`)                | value     | **derived**: `cargo-ai connection connector list` shows the authorized CRM. **asked** only when the workspace holds two                                                                      | The models read one CRM; the wrong one is a clean audit of the wrong deals                                                                                                                             |
| pipelines                                                 | value     | **derived** by the `pipelines` query: every pipeline is read and listed with its counts. **asked** in the first pull request only when there is more than one: which are the sales pipelines | Partner, renewal and support pipelines close deals too, and they are not the same evidence                                                                                                             |
| CRM hygiene findings                                      | value     | **derived** by the `lost_reasons` and `contacts_on_deals` quer
...[truncated 26 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 158)May include surrounding context.

md
| pipelines                                                 | value     | **derived** by the `pipelines` query: every pipeline is read and listed with its counts. **asked** in the first pull request only when there is more than one: which are the sales pipelines | Partner, renewal and support pipelines close deals too, and they are not the same evidence                                                                                                             |
| CRM hygiene findings                                      | value     | **derived** by the `lost_reasons` and `contacts_on_deals` queries and **stated**, never asked and never worked around                                                                        | The first decides whether objections can come from the CRM at all. The second says how many closed deals are blind for stakeholder mapping, so every title count is read against the right denominator |
| lost-reason property (`LOST_REASON_COLUMN`)               | value     | **derived**: HubSpot's standard `closed_lost_reason` ships. A fill rate of 0 of N with lost deals in the window is the cue to find the custom property and set it                            | Most portals record the reason on a custom property. Left wrong, the audit reports a team that never records reasons, and writes no objections, forever                                                |
| mode                                                      | value     | **derived**: `verify` at `VERIFY_MIN_WON` (20) or more won deals in the window, else `hypothesis`. Never asked                                                                               | The line is a number so nobody argues it per run                                                                                                                                                       |
| `icp/`, `insight/`, `objection/`, `client/`               | generated | **derived** from the queries, as the prompt describes; a seede
...[truncated 26 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 160)May include surrounding context.

md
| lost-reason property (`LOST_REASON_COLUMN`)               | value     | **derived**: HubSpot's standard `closed_lost_reason` ships. A fill rate of 0 of N with lost deals in the window is the cue to find the custom property and set it                            | Most portals record the reason on a custom property. Left wrong, the audit reports a team that never records reasons, and writes no objections, forever                                                |
| mode                                                      | value     | **derived**: `verify` at `VERIFY_MIN_WON` (20) or more won deals in the window, else `hypothesis`. Never asked                                                                               | The line is a number so nobody argues it per run                                                                                                                                                       |
| `icp/`, `insight/`, `objection/`, `client/`               | generated | **derived** from the queries, as the prompt describes; a seeded ICP gets one dated "Verified against the CRM" section on the first pass and is never edited after                            | The disqualifier is the half of an ICP that protects the team's time, and won versus lost is the only place it comes from with evidence                                                                |
| Slack channel (`infra/agents/win-loss-analyst.ts`)        | value     | **asked**: the channel the digest lands in, locked on the `postMessage` use. An id (`C…`), not a name                                                                                        | Locked so the agent cannot pick a customer shared channel; a digest about lost deals is internal                                                                                                       |
| repository binding (`infra/agents/win-loss-analyst.ts`)   | value     | **derived**: leave `repository` unset and `plan` fills it from
...[truncated 25 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 160)May include surrounding context.

md
| lost-reason property (`LOST_REASON_COLUMN`)               | value     | **derived**: HubSpot's standard `closed_lost_reason` ships. A fill rate of 0 of N with lost deals in the window is the cue to find the custom property and set it                            | Most portals record the reason on a custom property. Left wrong, the audit reports a team that never records reasons, and writes no objections, forever                                                |
| mode                                                      | value     | **derived**: `verify` at `VERIFY_MIN_WON` (20) or more won deals in the window, else `hypothesis`. Never asked                                                                               | The line is a number so nobody argues it per run                                                                                                                                                       |
| `icp/`, `insight/`, `objection/`, `client/`               | generated | **derived** from the queries, as the prompt describes; a seeded ICP gets one dated "Verified against the CRM" section on the first pass and is never edited after                            | The disqualifier is the half of an ICP that protects the team's time, and won versus lost is the only place it comes from with evidence                                                                |
| Slack channel (`infra/agents/win-loss-analyst.ts`)        | value     | **asked**: the channel the digest lands in, locked on the `postMessage` use. An id (`C…`), not a name                                                                                        | Locked so the agent cannot pick a customer shared channel; a digest about lost deals is internal                                                                                                       |
| repository binding (`infra/agents/win-loss-analyst.ts`)   | value     | **derived**: leave `repository` unset and `plan` fills it from
...[truncated 25 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 161)May include surrounding context.

md
| mode                                                      | value     | **derived**: `verify` at `VERIFY_MIN_WON` (20) or more won deals in the window, else `hypothesis`. Never asked                                                                               | The line is a number so nobody argues it per run                                                                                                                                                       |
| `icp/`, `insight/`, `objection/`, `client/`               | generated | **derived** from the queries, as the prompt describes; a seeded ICP gets one dated "Verified against the CRM" section on the first pass and is never edited after                            | The disqualifier is the half of an ICP that protects the team's time, and won versus lost is the only place it comes from with evidence                                                                |
| Slack channel (`infra/agents/win-loss-analyst.ts`)        | value     | **asked**: the channel the digest lands in, locked on the `postMessage` use. An id (`C…`), not a name                                                                                        | Locked so the agent cannot pick a customer shared channel; a digest about lost deals is internal                                                                                                       |
| repository binding (`infra/agents/win-loss-analyst.ts`)   | value     | **derived**: leave `repository` unset and `plan` fills it from the git origin of the checkout. `cargo-ai cdk check` prints what it resolved: confirm the repository root                     | This is the working tree the harness clones and the only place its output can land                                                                                                                     |
| LLM connector and model (`infra/connectors/anthropic.ts`) | value     | **derived**: `cargo-ai connection connector list` shows whethe
...[truncated 25 chars]

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 162)May include surrounding context.

md
| `icp/`, `insight/`, `objection/`, `client/`               | generated | **derived** from the queries, as the prompt describes; a seeded ICP gets one dated "Verified against the CRM" section on the first pass and is never edited after                            | The disqualifier is the half of an ICP that protects the team's time, and won versus lost is the only place it comes from with evidence                                                                |
| Slack channel (`infra/agents/win-loss-analyst.ts`)        | value     | **asked**: the channel the digest lands in, locked on the `postMessage` use. An id (`C…`), not a name                                                                                        | Locked so the agent cannot pick a customer shared channel; a digest about lost deals is internal                                                                                                       |
| repository binding (`infra/agents/win-loss-analyst.ts`)   | value     | **derived**: leave `repository` unset and `plan` fills it from the git origin of the checkout. `cargo-ai cdk check` prints what it resolved: confirm the repository root                     | This is the working tree the harness clones and the only place its output can land                                                                                                                     |
| LLM connector and model (`infra/connectors/anthropic.ts`) | value     | **derived**: `cargo-ai connection connector list` shows whether an Anthropic connector is authorized; the agent's `languageModel` is a placeholder to set                                    | A harness does not bring its own model; this is what the monthly run is billed and metered against                                                                                                     |

Checked before moving on, not after the deploy:

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 177)May include surrounding context.

md
waiting to be asked. Every one costs something; that is what makes it a variation and not the
default.

| Variation               | When it is right                                                                         | How                                                                                                                                                              | What it costs                                                                                                                  |
| ----------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `another_crm`           | The deals live in Salesforce or Attio                                                    | Change the connector, the three models' config and the queries together, following `references/crm-audit.md`                                                     | Field names vary per org, so the queries are rewritten against the live schema and the first pass is checked by eye            |
| `deal_contacts`         | Titles at won accounts are too broad, and the team wants the titles on the deals only    | Add `associationObjectTypes: ["contacts"]` to `crm-deals.ts`, read the column it creates after the sync, and replace `titles_at_won_accounts` with a query on it | One more column to keep in sync with the extractor's naming, and a query to re-check if the extractor changes it               |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 177)May include surrounding context.

md
waiting to be asked. Every one costs something; that is what makes it a variation and not the
default.

| Variation               | When it is right                                                                         | How                                                                                                                                                              | What it costs                                                                                                                  |
| ----------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `another_crm`           | The deals live in Salesforce or Attio                                                    | Change the connector, the three models' config and the queries together, following `references/crm-audit.md`                                                     | Field names vary per org, so the queries are rewritten against the live schema and the first pass is checked by eye            |
| `deal_contacts`         | Titles at won accounts are too broad, and the team wants the titles on the deals only    | Add `associationObjectTypes: ["contacts"]` to `crm-deals.ts`, read the column it creates after the sync, and replace `titles_at_won_accounts` with a query on it | One more column to keep in sync with the extractor's naming, and a query to re-check if the extractor changes it               |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · SKILL.md (reported line 181)May include surrounding context.

md
| ----------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `another_crm`           | The deals live in Salesforce or Attio                                                    | Change the connector, the three models' config and the queries together, following `references/crm-audit.md`                                                     | Field names vary per org, so the queries are rewritten against the live schema and the first pass is checked by eye            |
| `deal_contacts`         | Titles at won accounts are too broad, and the team wants the titles on the deals only    | Add `associationObjectTypes: ["contacts"]` to `crm-deals.ts`, read the column it creates after the sync, and replace `titles_at_won_accounts` with a query on it | One more column to keep in sync with the extractor's naming, and a query to re-check if the extractor changes it               |
| `raise_the_verify_line` | Twenty wins is too few to separate won from lost in your market (long cycles, few deals) | Raise `VERIFY_MIN_WON` in `infra/agents/win-loss-analyst.prompt.ts`                                                                                              | More months land in hypothesis mode, and the files assert less                                                                 |
| `wider_window`          | Your sales cycle is longer than a year, or last year was not representative              | Raise `WINDOW_DAYS` in the same file                                                                                                                             | Older deals describe an older market, and a two-year window on a company t
...[truncated 25 chars]

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

The prompt instructs the agent to run npx --yes @cargo-ai/cli if cargo-ai is not already installed, which fetches and executes the latest package version at runtime without pinning. That creates a supply-chain execution path: a compromised upstream package, malicious publish, or breaking update could cause arbitrary code execution in the agent environment with whatever repo, network, Slack, and CRM-adjacent permissions the agent has.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code contradicts its own data-minimization comment: it states the audit needs only titles and IDs and never email, yet the model is configured with columnSelectionMode: "all", which will ingest the full contacts schema. In a CRM context this commonly includes emails, phone numbers, and other personal data, creating unnecessary exposure, retention, and downstream misuse risk for a workflow that does not require those fields.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Extracting all contact fields is broader than justified for a monthly win-loss review whose stated purpose is ICP reconciliation based on titles and IDs. Over-collection increases the blast radius of any logging, sync, prompt injection into downstream agents, accidental sharing in Slack/context repos, or connector compromise, especially because CRM contact records often contain direct identifiers and sensitive business relationship data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This model is configured to extract all deal columns from the CRM into storage, which creates broad and unnecessary collection of potentially sensitive business and personal data. In this skill's context, the data is later queried by agents and the comments explicitly acknowledge that every property lands in storage, so a mistake in downstream queries, access controls, or future schema changes could expose confidential fields far beyond what the monthly win-loss review actually needs.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/crm-audit.md (reported line 9)May include surrounding context.

md
## The models

| Model          | Extractor                     | What it holds                                                                                                                        |
| -------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `crm_deals`    | `fetchRecords` on `deals`     | Every deal, open and closed, all columns. The queries narrow to closed deals (won or lost) and never select an amount                |
| `crm_accounts` | `fetchRecords` on `companies` | Every company, all columns. Declared as crm-enrichment and crm-deduplication declare it                                              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/crm-audit.md (reported line 26)May include surrounding context.

md
Each has a name, and every `[R: <name>, n of N]` tag in the context files cites one. The run record
under `outputs/` holds each result.

| Query                    | What it answers                                                                                       |
| ------------------------ | ----------------------------------------------------------------------------------------------------- |
| `pipelines`              | Won and lost per pipeline in the window. More than one pipeline is the one question the operator gets |
| `lost_reasons`           | Each lost reason and its count. The empty reason's count is the hygiene finding's complement          |

Static analysis

No suspicious patterns detected.