Back to skill

Security audit

call-capture

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says: it uses a scheduled repo-writing agent to turn recorded calls into reviewable repository updates, with sensitive access clearly disclosed.

Install only in a repository that is allowed to hold raw call transcripts. Set the internal email domain correctly, keep the recorder API key as a secret, verify the GitHub connector can write only where intended, pin the local tsx/tooling dependency, and review each generated pull request before merge.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents a full workflow for collecting call recordings, transforming them into context, and updating a repo. The supplied code chunk does none of that. It only creates an agent folder for organizational purposes in infrastructure code. This is not merely an implementation detail of the described behavior; it reflects a materially different and much narrower purpose than the declared skill description.

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/avoma.ts`. **On any other recorder, this step is a new file, not an edit.**
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/avoma.ts`. **On any other recorder, this step is a new file, not an edit.**
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/recorder.ts` — a `provider` slug plus `listReady(from, to)`, `transcript(id)`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/recorder.ts` — a `provider` slug plus `listReady(from, to)`, `transcript(id)`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/recorder.ts` — a `provider` slug plus `listReady(from, to)`, `transcript(id)`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/recorder.ts` — a `provider` slug plus `listReady(from, to)`, `transcript(id)`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`scripts/collect/recorder.ts` — a `provider` slug plus `listReady(from, to)`, `transcript(id)`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Env Variable Harvesting

High
Category
Data Exfiltration
Content
const API = "https://api.avoma.com/v1";

const API_KEY = process.env["CALL_RECORDER_API_KEY"];
if (API_KEY === undefined || API_KEY === "") {
  console.error(
    "CALL_RECORDER_API_KEY is not set. It comes from the agent's repository env " +
Confidence
70% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill describes network access, environment-secret use, scheduled execution, and repository writes, but it declares no explicit tool scope such as allowed tools or permissions. In a skill that pulls external transcripts and opens pull requests, missing scope boundaries increases the chance of overbroad runtime capabilities or unsafe deployment assumptions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The instruction to run `npx tsx` without a pinned version allows execution of whatever package version is currently resolved from the registry or environment. In a workflow handling API keys and repository write access, this creates a supply-chain risk where a compromised or unexpected package version could exfiltrate secrets or modify code during local verification or scheduled runs.

Whitespace Padding

Medium
Category
Prompt Injection
Content
**Derive before you ask.** An input with a lookup is looked up, not asked. Only the ones marked
_asked_ genuinely live in the operator's head.

| Input                                                        | Kind   | How it is answered                                                                                                                                                                                                                                     | Why it matters                                                                                                                                                                                                       |
| ------------------------------------------------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| repository binding (`infra/agents/call-scribe.ts`)           | value  | **derived**: leave `repository`, `defaultBranch` and `connector` unset and `plan` fills them from the git origin of the checkout, taking the GitHub connector from the project's own. `cargo-ai cdk check` prints what it resolved: confirm the line reads your repo and `./`.                | This is the working tree the harness clones and the only place its output can land. An `owner/name` written by hand is the one value nobody notices is wrong until a pull request opens against a stranger's repository.                                                |
| `CALL_RECORDER_API_KEY`                                              | env    | **asked**: the recorder's API key, exported before deploy and neve
...[truncated 25 chars]
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.

Whitespace Padding

Medium
Category
Prompt Injection
Content
**Derive before you ask.** An input with a lookup is looked up, not asked. Only the ones marked
_asked_ genuinely live in the operator's head.

| Input                                                        | Kind   | How it is answered                                                                                                                                                                                                                                     | Why it matters                                                                                                                                                                                                       |
| ------------------------------------------------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| repository binding (`infra/agents/call-scribe.ts`)           | value  | **derived**: leave `repository`, `defaultBranch` and `connector` unset and `plan` fills them from the git origin of the checkout, taking the GitHub connector from the project's own. `cargo-ai cdk check` prints what it resolved: confirm the line reads your repo and `./`.                | This is the working tree the harness clones and the only place its output can land. An `owner/name` written by hand is the one value nobody notices is wrong until a pull request opens against a stranger's repository.                                                |
| `CALL_RECORDER_API_KEY`                                              | env    | **asked**: the recorder's API key, exported before deploy and neve
...[truncated 25 chars]
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.

Whitespace Padding

Medium
Category
Prompt Injection
Content
| ------------------------------------------------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| repository binding (`infra/agents/call-scribe.ts`)           | value  | **derived**: leave `repository`, `defaultBranch` and `connector` unset and `plan` fills them from the git origin of the checkout, taking the GitHub connector from the project's own. `cargo-ai cdk check` prints what it resolved: confirm the line reads your repo and `./`.                | This is the working tree the harness clones and the only place its output can land. An `owner/name` written by hand is the one value nobody notices is wrong until a pull request opens against a stranger's repository.                                                |
| `CALL_RECORDER_API_KEY`                                              | env    | **asked**: the recorder's API key, exported before deploy and never committed. It is declared as a `secret()` in the agent's `repository.env`, so it reaches the collector as an environment variable and nothing else.                                  | It is the collector's only credential. Deploy without it set and `secret()` fails loudly at apply, which is the behaviour you want; hard-code it instead and it is in `cargo.state.json` forever.                     |
| `CALL_CAPTURE_INTERNAL_DOMAIN` (`infra/agents/call-scribe.ts`) | value  | **derived**: your own email domain, which the workspace members' addresses already name                                                                                                                      
...[truncated 26 chars]
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.

Whitespace Padding

Medium
Category
Prompt Injection
Content
| `CALL_RECORDER_API_KEY`                                              | env    | **asked**: the recorder's API key, exported before deploy and never committed. It is declared as a `secret()` in the agent's `repository.env`, so it reaches the collector as an environment variable and nothing else.                                  | It is the collector's only credential. Deploy without it set and `secret()` fails loudly at apply, which is the behaviour you want; hard-code it instead and it is in `cargo.state.json` forever.                     |
| `CALL_CAPTURE_INTERNAL_DOMAIN` (`infra/agents/call-scribe.ts`) | value  | **derived**: your own email domain, which the workspace members' addresses already name                                                                                                                                                                | It is how an internal call is told from a customer one. Avoma's `is_internal` is false on every meeting in some workspaces, so it cannot be used; leave the placeholder and every standup is captured as an account.  |
| recorder adapter (`scripts/collect/avoma.ts`)          | value  | **derived**: read which recorder is in the stack from the repo's own context or the workspace connectors. Avoma ships; anything else is one new file satisfying `Recorder` plus an import swap in `calls.ts`, per `references/providers.md`.               | The contract is compiler-enforced, so a half-written adapter fails to build rather than half-working. Pointed at the wrong API it fails on the first request, which is loud; pointed at the right API with a stale field name it captures nothing and reports a clean empty run every morning. |
| GitHub connector (`infra/connectors/git.ts`)                 | value  | **derived**: `cargo-ai connection connector list` shows whether one is authorized; if not, `cargo-ai cdk add connector/github` opens the OAuth consent. The declaration is `adopt: true` because a deploy cannot mint an OAuth gra
...[truncated 25 chars]
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.

Whitespace Padding

Medium
Category
Prompt Injection
Content
| `CALL_CAPTURE_INTERNAL_DOMAIN` (`infra/agents/call-scribe.ts`) | value  | **derived**: your own email domain, which the workspace members' addresses already name                                                                                                                                                                | It is how an internal call is told from a customer one. Avoma's `is_internal` is false on every meeting in some workspaces, so it cannot be used; leave the placeholder and every standup is captured as an account.  |
| recorder adapter (`scripts/collect/avoma.ts`)          | value  | **derived**: read which recorder is in the stack from the repo's own context or the workspace connectors. Avoma ships; anything else is one new file satisfying `Recorder` plus an import swap in `calls.ts`, per `references/providers.md`.               | The contract is compiler-enforced, so a half-written adapter fails to build rather than half-working. Pointed at the wrong API it fails on the first request, which is loud; pointed at the right API with a stale field name it captures nothing and reports a clean empty run every morning. |
| GitHub connector (`infra/connectors/git.ts`)                 | value  | **derived**: `cargo-ai connection connector list` shows whether one is authorized; if not, `cargo-ai cdk add connector/github` opens the OAuth consent. The declaration is `adopt: true` because a deploy cannot mint an OAuth grant.                    | It is the agent's entire write path. Without it the run does the work and has nowhere to put it.                                                                                                                      |
| cadence and context paths                                    | value  | **derived**: read `cadence/README.md` and `context/README.md`, and `ls cadence/log/` for what already exists                                                                                                                              
...[truncated 25 chars]
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.

Whitespace Padding

Medium
Category
Prompt Injection
Content
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                                                                                                                                                                                                                     |
| ------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `notes-not-transcripts` | The repo is growing faster than you want, or your recorder's AI notes are genuinely good                | Reorder the fallback in `collect/calls.ts` so notes are fetched first and the transcript is the fallback                                                                                | You lose the verbatim record, so the scribe can no longer quote and nobody can check a summary against what was actually said. Notes are already an interpretation; scribing them is interpreting an interpretation                 |
| `raise-the-bar`     | Your context is filling with claims that turn out to be one customer's opinion                            | Raise the repetition bar in `infra/agents/call-scribe.prompt.ts` from two independent occurrences to three, and requir
...[truncated 25 chars]
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.

Static analysis

No suspicious patterns detected.