Back to skill

Security audit

Sre Publish

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised AWS SRE reporting workflow, but it can send raw DLQ message content to Bedrock and Telegram without redaction or clear consent controls.

Review before installing. Use only with DLQs whose message bodies are safe to share with Bedrock and the configured Telegram chat, or patch the skill to redact/disable DLQ samples before enabling it in production. Prefer a least-privilege IAM role scoped to the exact queues, functions, and Bedrock model, and treat generated AWS CLI CTAs as untrusted guidance to review manually.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
src/diagnosis.ts:45
Finding
Unredacted DLQ Content Disclosed to Bedrock and Telegram<![CDATA[ ## Vulnerability Details **File Locations**: - `src/metrics.ts:43-57` - `src/diagnosis.ts:45-54` - `src/diagnosis.ts:71-85` - `src/diagnosis.ts:95-99` - `src/reporter.ts:75-86` - `src/reporter.ts:98-102` - `src/reporter.ts:181-198` **Vulnerability Type**: Sensitive data exposure through external services **Risk Level**: High ### Vulnerable Code `src/metrics.ts:43-57`: ```typescript export async function peekDlqMessage( sqs: SQSClient, dlqUrl: string, ): Promise<string | null> { try { const resp = await sqs.send( new ReceiveMessageCommand({ QueueUrl: dlqUrl, MaxNumberOfMessages: 1, VisibilityTimeout: 10, WaitTimeSeconds: 1, }), ); const body = resp.Messages?.[0]?.Body; return body ? body.slice(0, 800) : null; } catch { return null; } } ``` `src/diagnosis.ts:45-54`: ```typescript const lines: string[] = [ `Detected issues: ${issues.join(" | ")}`, `AWS Region: ${region}`, `DLQ URL: ${dlqUrl}`, `Queue URL: ${queueUrl}`, ]; if (dlqSample) { lines.push(`DLQ message sample (1 msg): ${dlqSample}`); } ``` `src/diagnosis.ts:71-85`: ```typescript const body = JSON.stringify({ anthropic_version: "bedrock-2023-05-31", max_tokens: 400, system: SYSTEM_PROMPT, messages: [{ role: "user", content: lines.join("\n") }], }); try { const resp = await bedrockClient.send( new InvokeModelCommand({ modelId, contentType: "application/json", accept: "application/json", body: Buffer.from(body), }), ); ``` `src/diagnosis.ts:95-99`: ```typescript return { contexto: issues.join(". "), solucoes: dlqSample ? [`DLQ sample read: ${dlqSample.slice(0, 120)}…`] : [], ctas: [ ``` `src/reporter.ts:75-86`: ```typescript if (incident) { msg += `\n🔴 *Incident Detected*\n`; msg += `\n*Context*\n${esc(incident.contexto)}\n` ...[truncated 2988 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not retrieve or transmit raw DLQ bodies by default. Make payload inspection an explicit, opt-in configuration. 2. Parse messages locally and construct diagnosis input from an allowlist of non-sensitive fields such as error type, schema-validation path, event timestamp, and sanitized status code. 3. Recursively redact common sensitive fields, including passwords, API keys, authorization headers, cookies, access tokens, email addresses, phone numbers, and customer identifiers. 4. Apply pattern-based secret detection to unstructured content before invoking Bedrock. 5. Perform truncation only after redaction so that a secret at the beginning of a message cannot bypass protection. 6. Remove raw `dlqSample` content from the fallback incident. Report only that a sample was available and provide a safe operator workflow for inspecting it within AWS. 7. Add separate configuration controls for sharing sanitized diagnostics with Bedrock and Telegram. 8. Document the external data recipients, expected retention behavior, and data-classification requirements. 9. Add tests proving that sensitive fields and token-like strings never appear in Bedrock requests or Telegram report text. ]]>

other

Warning
Location
src/diagnosis.ts:45
Finding
Indirect Prompt Injection Through Untrusted DLQ Messages<![CDATA[ ## Vulnerability Details **File Locations**: - `src/diagnosis.ts:45-65` - `src/diagnosis.ts:71-92` - `src/reporter.ts:81-84` **Vulnerability Type**: Indirect prompt injection into operational recommendations **Risk Level**: Medium ### Vulnerable Code `src/diagnosis.ts:45-65`: ```typescript const lines: string[] = [ `Detected issues: ${issues.join(" | ")}`, `AWS Region: ${region}`, `DLQ URL: ${dlqUrl}`, `Queue URL: ${queueUrl}`, ]; if (dlqSample) { lines.push(`DLQ message sample (1 msg): ${dlqSample}`); } const failing = lambdaErrors.filter(e => e.count > 0); if (failing.length > 0) { lines.push( `Lambda functions with errors: ${failing.map(e => `${e.name} (${e.count} errors)`).join(", ")}`, ); } const bedrockClient = new BedrockRuntimeClient({ region: bedrockRegion ?? region }); ``` `src/diagnosis.ts:71-92`: ```typescript const body = JSON.stringify({ anthropic_version: "bedrock-2023-05-31", max_tokens: 400, system: SYSTEM_PROMPT, messages: [{ role: "user", content: lines.join("\n") }], }); try { const resp = await bedrockClient.send( new InvokeModelCommand({ modelId, contentType: "application/json", accept: "application/json", body: Buffer.from(body), }), ); const raw = JSON.parse(Buffer.from(resp.body).toString()) as { content: Array<{ text: string }> }; const text = raw.content[0].text.trim() .replace(/^```(?:json)?\n?/, "") .replace(/\n?```$/, ""); return JSON.parse(text) as Incident; ``` `src/reporter.ts:81-84`: ```typescript if (incident.ctas.length > 0) { msg += `\n*Next Actions*\n`; incident.ctas.forEach((cta, i) => { msg += ` ${i + 1}\\. ${esc(cta)}\n`; }); } ``` ### Technical Analysis The body of a DLQ message is attacker-controlled or otherwise untrusted application data. It is concatenated directly into the Bedrock user ...[truncated 2386 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every DLQ body as hostile data. Place it in a clearly delimited data block and explicitly instruct the model never to follow instructions found within that block. 2. Prefer extracting structured, allowlisted diagnostic facts locally instead of giving arbitrary message text to the model. 3. Validate model responses with a strict runtime schema. Enforce exact object keys, string length limits, array limits, and expected primitive types. 4. Generate AWS CLI commands from trusted application templates rather than accepting arbitrary model-generated command strings. 5. If model-generated commands remain supported, parse and allowlist permitted executables, AWS services, operations, options, regions, and resource identifiers. 6. Prefer read-only diagnostic commands. Clearly mark all mutation commands and require a separate manual approval step. 7. Reject shell metacharacters, command substitution, redirection, pipelines, multiline commands, and unexpected URLs in generated CTAs. 8. Separate model-authored analysis from executable instructions in the Telegram presentation and label model output as untrusted guidance. 9. Add adversarial tests using DLQ bodies that request system-prompt override, secret disclosure, destructive commands, and misleading incident suppression. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Content
coes.forEach(s => { msg += `  ✓ ${esc(s)}\n`; });
    }

    if (incident.ctas.length > 0) {
      msg += `\n*Next Actions*\n`;
      incident.ctas.forEach((cta, i) => { msg += `  ${i + 1}\\. ${esc(cta)}\n`; });
    }
  }

  return msg;
}

/** Sends a MarkdownV2 message to Telegram. */
async function sendTelegram(token: string, chatId: string, text: string): Promise<void> {
  const resp = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
    method:  "POST",
    headers: { "Content-Type": "application/json" },
    body:    JSON.stringify({ chat_id: chatId, text, parse_mode: "MarkdownV2" }),
  });
  if (!resp.ok) {
    throw new Error(`Telegram sendMessage failed: ${resp.status} ${await resp.text()}`);
  }
}

/**
 * Main SRE reporter.
 *
 * @example
 * const reporter = new SreReporter({
 *   region:           "us-east-1",
 *   telegramBotToken: process.env.TELEGRAM_BOT_TOKEN!,
 *   telegramChatId:   process.env.TELEGRAM_CHAT_ID!,
 *   dlqUrl:           process.env.DLQ_
Confidence
85% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description presents a multi-part AWS SRE health-check and reporting workflow involving CloudWatch, SQS DLQ, Cost Explorer, Bedrock analysis, and Telegram delivery. The supplied code chunk only accesses Cost Explorer and computes yesterday's per-service spend plus month-to-date total. It does not query CloudWatch, inspect SQS DLQs, invoke Bedrock, or send anything to Telegram. While this code is consistent with the FinOps subset of the description, the actual behavior of the chunk is materially narrower than the declared end-to-end skill purpose, so this should be flagged as a mismatch for description-versus-behavior at the code-chunk level.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README explicitly states that AWS health, incident, and cost information is sent to Telegram, an external third-party messaging platform, but it does not warn users about the data egress, sensitivity of the contents, or the trust boundary involved. In an SRE/FinOps context, these reports can expose operational metadata, spending patterns, queue state, and diagnostic details that may be sensitive in production environments.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares environment-variable and network-dependent behavior but does not define an explicit tool/permission scope. In an agent environment, that can lead to overbroad execution authority or unclear review boundaries, especially since the skill accesses AWS and Telegram credentials and sends outbound reports.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The description specifies a Bedrock-powered incident diagnosis in the fixed format "Contexto, Soluções, CTAs," which indicates a specific language/locale choice. There is no indication that users can opt into another language or that the Portuguese output is required for a documented regional purpose.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The activation phrases are broad enough that ordinary requests like infrastructure status or cost overview could trigger the skill unintentionally. Because this skill uses sensitive AWS environment configuration and performs external reporting to Telegram, accidental invocation could expose operational data or cause unreviewed outbound actions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code sends incident context, DLQ message samples, queue URLs, and Lambda error details to an external managed LLM service without any visible minimization, redaction, or consent gate in this file. DLQ samples commonly contain payload data, identifiers, secrets, or customer content, so this creates a real data exposure risk to a third-party processing boundary even if Bedrock remains within AWS.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The report formats incident content using Portuguese-named fields like `contexto` and `solucoes` while the rest of the skill is otherwise English, implying a fixed locale assumption in the generated/reporting flow. The file does not offer a user language choice or document that the skill is intentionally region-specific, which matches the language/locale policy violation criteria.

External Transmission

Medium
Category
Data Exfiltration
Content
/** Sends a MarkdownV2 message to Telegram. */
async function sendTelegram(token: string, chatId: string, text: string): Promise<void> {
  const resp = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
    method:  "POST",
    headers: { "Content-Type": "application/json" },
    body:    JSON.stringify({ chat_id: chatId, text, parse_mode: "MarkdownV2" }),
Confidence
88% confidence
Finding
The skill transmits operational and potentially sensitive incident content to an external third-party service (Telegram). Because the report may include DLQ samples, Lambda error details, costs, and AI-generated incident context, this creates a real data egress path outside AWS that could expose internal metadata or sensitive payload fragments if misconfigured or over-shared.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The description says the incident report is delivered with section headings such as "Contexto" and "Soluções Aplicadas," implying a fixed Portuguese output format. There is no indication that users can choose the report language or that the locale restriction is intentional and documented.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"node": ">=20.0.0"
  },
  "dependencies": {
    "@aws-sdk/client-bedrock-runtime": "^3.600.0",
    "@aws-sdk/client-cloudwatch": "^3.600.0",
    "@aws-sdk/client-cost-explorer": "^3.600.0",
    "@aws-sdk/client-sqs": "^3.600.0"
Confidence
92% confidence
Finding
Using caret ranges for runtime dependencies allows future installs to resolve newer package versions than were originally tested. In a skill that interacts with AWS services and generates incident reports, an upstream compromised or breaking release could introduce supply-chain risk or unexpected behavior at deployment time.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "@aws-sdk/client-bedrock-runtime": "^3.600.0",
    "@aws-sdk/client-cloudwatch": "^3.600.0",
    "@aws-sdk/client-cost-explorer": "^3.600.0",
    "@aws-sdk/client-sqs": "^3.600.0"
  },
Confidence
92% confidence
Finding
The CloudWatch client dependency is version-ranged with a caret, so rebuilds may pull in unreviewed newer releases. Because this package is used in AWS operational monitoring, a malicious or flawed upstream update could affect telemetry collection or report generation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"dependencies": {
    "@aws-sdk/client-bedrock-runtime": "^3.600.0",
    "@aws-sdk/client-cloudwatch": "^3.600.0",
    "@aws-sdk/client-cost-explorer": "^3.600.0",
    "@aws-sdk/client-sqs": "^3.600.0"
  },
  "devDependencies": {
Confidence
92% confidence
Finding
The Cost Explorer SDK dependency is not strictly pinned, which weakens build reproducibility and increases exposure to supply-chain compromise or incompatible upstream changes. Given this skill handles cost and health reporting, silent dependency drift could alter financial reporting or runtime stability.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"@aws-sdk/client-bedrock-runtime": "^3.600.0",
    "@aws-sdk/client-cloudwatch": "^3.600.0",
    "@aws-sdk/client-cost-explorer": "^3.600.0",
    "@aws-sdk/client-sqs": "^3.600.0"
  },
  "devDependencies": {
    "@types/jest": "^29.5.0",
Confidence
92% confidence
Finding
The SQS client dependency can float to later compatible versions under semver, which means new code may be introduced without explicit review. For an automation component that inspects DLQs, this creates a low but real supply-chain and reliability risk.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"@aws-sdk/client-sqs": "^3.600.0"
  },
  "devDependencies": {
    "@types/jest": "^29.5.0",
    "@types/node": "^22.0.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.0",
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "devDependencies": {
    "@types/jest": "^29.5.0",
    "@types/node": "^22.0.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.0",
    "typescript": "^5.7.0"
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"devDependencies": {
    "@types/jest": "^29.5.0",
    "@types/node": "^22.0.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.0",
    "typescript": "^5.7.0"
  }
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"@types/jest": "^29.5.0",
    "@types/node": "^22.0.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.0",
    "typescript": "^5.7.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"@types/node": "^22.0.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.0",
    "typescript": "^5.7.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The prompt instructs the model to 'Write in the same language as the user context (Portuguese if context is in PT-BR, English otherwise).' This hard-codes English as the default for all non-PT-BR contexts, rather than offering a language choice or clearly documenting a justified locale restriction.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
The `Incident` interface uses natural-language field names `contexto` and `solucoes`, which signals a fixed locale/language choice in the skill’s generated incident content structure. In this file there is no indication that users can choose the language or that the Portuguese-specific naming is required for a documented regional use case.

Static analysis

No suspicious patterns detected.