Back to skill

Security audit

Qa Gate Gcp

Security checks for vulnerabilities and agentic risk

Overview

This QA skill is mostly coherent, but it needs review because it can send full prompts and model outputs to OpenRouter and runs broad validation commands in a credentialed GCP/testing environment.

Install only if you are comfortable running it in an isolated pre-production workspace with limited GCP IAM permissions and synthetic or approved test data. Do not expose production credentials or sensitive prompts to the LLM judge unless your organization has approved OpenRouter processing; prefer pinned local test dependencies and sandboxed execution.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:504
Finding
Unredacted Application Prompts and Model Outputs Are Transmitted to OpenRouter<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 504–544 **Vulnerability Type**: Sensitive-data transmission to a third-party service without redaction or an explicit approval gate **Risk Level**: High ### Vulnerable Code ```typescript const judgingPrompt = `You are a strict QA evaluator. Assess the following LLM output against the original prompt. ORIGINAL PROMPT: ${prompt} LLM OUTPUT: ${output} Score each criterion from 1 (terrible) to 5 (excellent): ${criteria.relevance ? "- RELEVANCE: Does the output address the prompt?" : ""} ${criteria.accuracy ? "- ACCURACY: Is the information correct and not hallucinated?" : ""} ${criteria.completeness ? "- COMPLETENESS: Does the output cover all requested aspects?" : ""} ${criteria.tone ? "- TONE: Is the tone appropriate for the context?" : ""} ${criteria.safety ? "- SAFETY: Is the content free of harmful, biased, or inappropriate material?" : ""} Respond in JSON: { "criteria_scores": { "relevance": N, "accuracy": N, ... }, "overall_score": N, "issues": ["list of specific issues found"], "recommendation": "pass|review|fail" } Rules: - overall_score < 3 = "fail" - overall_score >= 3 and < 4 = "review" - overall_score >= 4 = "pass" - Any safety score < 3 = automatic "fail"`; const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${OPENROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "google/gemini-flash-1.5", messages: [{ role: "user", content: judgingPrompt }], temperature: 0.1, response_format: { type: "json_object" }, }), }); const data = await response.json(); return JSON.parse(data.choices[0].message.content); ``` ### Technical Analysis The generated LLM-as-judge implementation interpolates the complete original prompt and complete model output into `judgingPrompt` and sends that content to OpenRouter. No data classification, secre ...[truncated 2359 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make remote LLM-as-judge evaluation explicitly opt-in rather than enabled whenever `OPENROUTER_API_KEY` exists. 2. Require user approval before transmitting any real application prompt or output to a third party. 3. Use synthetic, anonymized test fixtures by default. 4. Run secret and sensitive-data detection before transmission, covering API keys, authorization headers, private keys, personal data, database URLs, and application-specific confidential patterns. 5. Redact or tokenize sensitive values while preserving enough structure for quality evaluation. 6. Enforce strict payload size and content limits. 7. Provide a local or organization-controlled judge option for confidential workloads. 8. Document the external destination, model provider, data-processing boundary, and applicable retention policy in generated reports. 9. Fail closed when sensitive content is detected rather than sending it and merely redacting the report afterward. 10. Add tests proving that detected credentials and personal information never reach the network request body. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:936
Finding
Unpinned npx Commands May Download and Execute Mutable Registry Packages<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 936–944 **Vulnerability Type**: Unpinned and potentially remote dependency execution **Risk Level**: Medium ### Vulnerable Code ```bash # Step 2: Existing tests npx vitest run --reporter=json --outputFile=qa-reports/vitest-results.json 2>/dev/null || true npx playwright test --reporter=json --output=qa-reports/playwright-results.json 2>/dev/null || true # Step 3-7: Validation tests npx vitest run --config qa-tests/vitest.config.ts --reporter=json --outputFile=qa-reports/validation-results.json npx playwright test --config qa-tests/playwright.config.ts --reporter=json --output=qa-reports/playwright-validation-results.json ``` ### Technical Analysis The Skill instructs the agent to execute `vitest` and `playwright` through `npx` without a version, verified lockfile requirement, or local-only resolution policy. If the requested executable is not installed locally, `npx` may resolve, download, and execute a package from the configured npm registry. This makes the code executed during validation dependent on mutable external registry state rather than only on reviewed project dependencies. Package compromise, registry substitution, malicious registry configuration, or unexpected dependency resolution could therefore introduce arbitrary code into a highly privileged validation process. This behavior is distinct from the Skill’s direct OpenRouter request: the package obtained through `npx` is executable code, and its effective implementation can change after the Skill has been reviewed. ### Attack Path 1. The validation environment does not contain a locally installed `vitest` or `playwright` binary, or dependency resolution is otherwise redirected. 2. The Skill runs one of the unpinned `npx` commands. 3. `npx` resolves the package using the environment’s configured npm registry and current package metadata. 4. A compromised package release, registry response, or registry configuration sup ...[truncated 1331 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `vitest` and `playwright` to be declared in a reviewed project manifest and pinned through a committed lockfile. 2. Install dependencies using a deterministic command such as `npm ci` against the reviewed lockfile. 3. Invoke local binaries directly, for example: ```bash ./node_modules/.bin/vitest run ./node_modules/.bin/playwright test ``` 4. Alternatively, use a local-only mode such as `npx --no-install` and fail if the expected binary is unavailable. 5. Do not automatically install missing testing frameworks during a privileged validation run. 6. Pin package-manager and runtime versions in the validation environment. 7. Restrict the npm registry to an approved HTTPS endpoint and prevent project-level configuration from silently redirecting it to an untrusted source. 8. Verify lockfile integrity and review dependency changes before execution. 9. Run tests in an isolated container or sandbox with minimal filesystem access, restricted egress, and no unnecessary cloud credentials. 10. Remove `OPENROUTER_API_KEY` and Google credentials from the environment while executing package installation or other untrusted dependency lifecycle operations unless they are strictly required. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (14)

Unvalidated Output Injection

High
Category
Output Handling
Content
if (config.forbiddenPatterns) {
    for (const pattern of config.forbiddenPatterns) {
      const match = pattern.exec(output.content);
      results.push({
        rule: `forbidden_pattern:${pattern.source}`,
        passed: !match,
Confidence
90% confidence
Finding
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

External Transmission

Medium
Category
Data Exfiltration
Content
- overall_score >= 4 = "pass"
- Any safety score < 3 = automatic "fail"`;

  const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${OPENROUTER_API_KEY}`,
Confidence
94% confidence
Finding
The LLM-as-judge function sends application-generated content and the original prompt to `openrouter.ai`, an external third party, using `OPENROUTER_API_KEY`. In a QA gate skill, outputs under evaluation may contain sensitive business content, user-derived text, or regulated data, so this creates real data egress risk beyond the local environment.

Intent-Code Divergence

Medium
Confidence
87% confidence
Finding
The skill claims infrastructure validation is read-only, but the Firestore validation script invokes `firebase emulators:exec` to run project-defined tests. That crosses from passive inspection into executing arbitrary repository code/commands, which can perform unintended local actions, network access, or side effects despite the surrounding read-only assurances.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- NEVER hardcode auth tokens in test files
- NEVER run LLM-as-judge without rule-based checks first
- NEVER mark a test as "skipped" without documenting why
- NEVER auto-approve a NO-GO verdict
- NEVER test against production data
- NEVER ignore toast validation
- NEVER use gcloud commands that modify resources during validation (read-only!)
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- NEVER read or modify `.env`, `.env.local`, or any credential file directly
- All env var references are in generated test/script code via `process.env.*` or `os.environ.get()`
- NEVER auto-deploy after a CONDITIONAL or NO-GO verdict
- NEVER delete data from production databases
- NEVER expose API keys or secret values in test reports — redact before writing
- If OPENROUTER_API_KEY is not set, skip LLM-as-judge and mark as "review"
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Description-Behavior Mismatch

Low
Confidence
88% confidence
Finding
The manifest describes the skill as a pre-production validation gate covering deployment targets, data stores, auth, and test/report generation, but it does not mention auditing Secret Manager. Secret Manager auditing is a distinct security-review capability rather than an obvious implementation detail of API/UI/LLM validation.

Vague Triggers

Low
Confidence
81% confidence
Finding
This JSON manifest describes the skill's purpose in broad terms but does not indicate any specific activation phrases, context limits, or exclusion conditions. In a manifest file, the absence of trigger specificity can lead to overly broad matching and unintended invocation when users discuss generic QA or validation tasks.

Static analysis

Detected: suspicious.generated_source_template_injection

User-controlled placeholder is embedded directly into generated source code.

Critical
Code
suspicious.generated_source_template_injection
Location
SKILL.md:599