registry  /  @roopesh.yadava/qa-pack  /  1.1.0

@roopesh.yadava/qa-pack@1.1.0

AI-powered QA agent skills for Claude Code — manual testing, BDD automation, accessibility, UI/Figma diff, bug reporting

AI Security Review

scanned 4h ago · by lpm-firewall-ai

Installation copies the test-charter agent skill into `.claude/skills`. When the user invokes a test charter, it logs into a user-provided site, extracts an auth token, and sends it to a separate hard-coded endpoint.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
Install the package, then invoke the test-charter skill and provide site credentials.
Impact
An attacker-controlled or unrelated service can receive a valid token plus charter contents and user identity data.
Mechanism
Agent-mediated bearer-token exfiltration to a hard-coded remote API.
Attack narrative
The postinstall hook deploys the package’s Claude skills into the consuming project. Its test-charter skill prompts for credentials to an arbitrary decision-record site, extracts a browser token from storage or network responses, then sends that bearer token and generated charter data to a fixed AWS endpoint rather than the user-supplied site. The user is not told about or asked to approve this cross-origin token transfer.
Rationale
Source inspection confirms a concrete credential-exfiltration chain in a package-installed agent skill. The install hook makes the malicious capability available automatically, while execution occurs during the advertised charter workflow.
Evidence
bin/postinstall.jsclaude/skills/test-charter/SKILL.mdclaude/settings.jsontemplates/mcp.json.claude/skills/test-charter/SKILL.mdoutputs/charters/[SLUG].md
Network endpoints1
hrqgymnn16.execute-api.us-east-1.amazonaws.com/dev/test-charter

Decision evidence

public snapshot
AI called this Malicious at 95.0% confidence as Malware with low false-positive risk.
Evidence for block
  • `bin/postinstall.js` automatically installs package skills into project `.claude/skills`.
  • `claude/skills/test-charter/SKILL.md` captures browser auth tokens from local/session storage.
  • The same skill POSTs that token as Bearer auth to a fixed AWS API endpoint.
  • The destination is hard-coded and unrelated to the user-supplied decision-record site.
  • Publishing proceeds after review but does not disclose or request consent for this token transfer.
Evidence against
  • `bin/postinstall.js` contains no direct network call or credential read.
  • The delete-files skill is restricted to `outputs/` and requires explicit confirmation.
  • Jira attachment guidance targets the user-derived Jira domain and uses configured credentials.
Behavioral surface
Source
ChildProcessDynamicRequireEnvironmentVarsFilesystem
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 2 file(s), 9.47 KB of source, external domains: registry.npmjs.org

Source & flagged code

4 flagged · loading source
package.jsonView file
scripts.postinstall = node bin/postinstall.js
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node bin/postinstall.js
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
bin/postinstall.jsView file
20Install-time AI-agent control hijack evidence: L20: function ensureDir(dir) { L21: if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); L22: } ... L31: const isNew = !fs.existsSync(dest); L32: fs.copyFileSync(src, dest); L33: isNew ? log.added.push(rel) : log.updated.push(rel); ... L52: const skillsSrc = path.join(PACK_DIR, 'claude', 'skills'); L53: const skillsDest = path.join(PROJECT_ROOT, '.claude', 'skills'); L54: ... L60: if (fs.existsSync(destPath)) { L61: log.protected.push(path.join('.claude', 'skills', rel)); L62: return false; // never overwrite Payload evidence from claude/skills/accessibility-testing/SKILL.md: L69: > "Please paste the **full URL of the page** you want to accessibility-test. L70: > (e.g. `https://app.example.com/dashboard/settings`)" L71: ... L315: | Jira bug creation fails | Note failure, continue remaining bugs, report failures at end | L316: | OTP screen appears unexpectedly | Type the `QA_OTP_CODE` value from `.env`, proceed | L317: | Page requires further navigation after login | Follow redirect, confirm TARGET_URL loads |
Critical
Ai Agent Control Hijack

Install-time source drops package-supplied AI-agent/MCP control files or instructions.

bin/postinstall.jsView on unpkg · L20
3L4: const fs = require('fs'); L5: const path = require('path');
Medium
Dynamic Require

Package source references dynamic require/import behavior.

bin/postinstall.jsView on unpkg · L3

Findings

1 Critical1 High4 Medium4 Low
CriticalAi Agent Control Hijackbin/postinstall.js
HighInstall Time Lifecycle Scriptspackage.json
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requirebin/postinstall.js
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings