qa-only
“Report-only QA testing. (gstack)”
aipkg.jsonLICENSE.txtREADME.mdSKILL.mdSKILL.md.tmpl- 01SDI-185%HIGH
SKILL.md:5
detailhide
The skill's manifest declares 'report-only QA testing' with a narrow scope, but the preamble executes extensive side effects: telemetry collection, configuration writes, analytics logging, and system state mutations (creating sessions, managing .gstack directories). This violates the principle of least privilege and the stated intent. A user invoking /qa-only expecting a harmless browser test could unknowingly participate in data collection and config changes. The contrast between declared and actual scope is dangerous because it hides non-obvious behaviors.
3preamble-tier: 44version: 1.0.05description: Report-only QA testing. (gstack)6allowed-tools:7 - Bashfix Separate telemetry and setup logic into an optional initialization step before preamble execution. Add explicit AskUserQuestion gates for all side effects (telemetry opt-in, analytics tracking, config writes). Document all mutations in the manifest description. Consider moving analytics to an opt-out model with clear disclosure at skill start, not buried in preamble.
- 02SDI-290%HIGH
SKILL.md:6
detailhide
The manifest grants unrestricted Bash tool access to a skill described as 'report-only QA testing'. The preamble invokes numerous external binaries without validation (gstack-update-check, gstack-config, find, rm, curl, git, jq, gbrain). Any of these paths can be hijacked via PATH manipulation, symlink attacks, or compromised binaries. An attacker controlling ~/.gstack/ or ~/.claude/skills/gstack/ can execute arbitrary code. The skill's declared narrowness makes developers trust it, but Bash access negates all boundaries.
4version: 1.0.05description: Report-only QA testing. (gstack)6allowed-tools:7 - Bash8 - Readfix Remove Bash from allowed-tools entirely if QA-only genuinely means browser-based testing. If Bash is required for environment detection, constrain it: (1) use absolute paths only for external binaries, (2) validate SHA256 checksums of binary downloads, (3) restrict rm/find to .gstack/ and .claude/ only, (4) add explicit allowlists for which binaries can be called, (5) remove 'true' fallbacks that silently ignore errors. Audit every external binary invocation for injection vulnerabilities.
- 03SDI-375%MEDIUM
SKILL.md:6
detailhide
The manifest allows Write tool with no scope constraints. The skill instructions at line 1160+ say 'Never fix bugs' and 'Do not read source code, edit files, or suggest fixes', yet the Write tool permits modifying any file. An attacker or confused user could invoke the skill with malicious input that causes unintended file modifications. The gap between the declared 'report-only' behavior and the unrestricted Write grant is a privilege escalation vector.
4version: 1.0.05description: Report-only QA testing. (gstack)6allowed-tools:7 - Bash8 - Readfix Remove Write from allowed-tools, or replace it with a scoped variant that writes only to .gstack/qa-reports/ and excludes source code directories. Add explicit file-path validation in any workflow that uses Write. Document that QA-only does not edit application code.
- 04SQP-275%MEDIUM
SKILL.md.tmpl:82
detailhide
The skill writes QA reports and screenshots to disk in predictable locations (.gstack/qa-reports/) without explicit user confirmation. This could lead to sensitive test data, credentials in screenshots, or application state information being persisted to disk without the user's informed consent, especially in shared or less-secure environments.
80## Output8182Write the report to both local and project-scoped locations:8384**Local:** `.gstack/qa-reports/qa-report-{domain}-{YYYY-MM-DD}.md`fix Add an explicit confirmation step before writing any reports or screenshots to disk. Implement a --dry-run mode by default that only displays findings without persisting them. Provide options to specify custom secure output directories and implement encryption for sensitive artifacts.
- 05RA2Session Persistence70%MEDIUM
SKILL.md:36
detailhide
The preamble creates session tracking files in ~/.gstack/sessions/ and logs usage to ~/.gstack/analytics/skill-usage.jsonl without explicit user consent shown at skill invocation time. While telemetry prompts exist later in the preamble, data collection begins immediately. This creates a window where users are unknowingly generating analytics records before they opt in or out. Session persistence combined with automatic writes violates transparency.
```bash _UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) [ -n "$_UPD" ] && echo "$_UPD" || true mkdir -p ~/.gstack/sessions touch ~/.gstack/sessions/"$PPID" _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || truefix Gate all telemetry and session tracking behind a synchronous AskUserQuestion at the start of the preamble, before any writes to ~/.gstack/. Show the user exactly what data will be collected and stored. Respect their choice before logging anything. Implement a 'dry-run' flag to show what would be logged without writing.
- 06RA2Session Persistence65%MEDIUM
SKILL.md:64
detailhide
Line 64-67 writes telemetry records to ~/.gstack/analytics/skill-usage.jsonl unconditionally if TEL is not 'off', even before the user is asked about telemetry. The telemetry prompt appears much later (line 223+). This creates an initial analytics write that happens before consent is collected, violating privacy principles and potentially breaching regulations like GDPR.
echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL" _QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false") echo "QUESTION_TUNING: $_QUESTION_TUNING" mkdir -p ~/.gstack/analytics if [ "$_TEL" != "off" ]; then echo '{"skill":"qa-only","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true fifix Defer all analytics writes until AFTER telemetry consent is obtained. Move the skill-usage.jsonl append to after the telemetry AskUserQuestion decision. Implement retroactive deletion: if the user declines telemetry, remove any analytics records written before their choice.
- 07TM1Tool Parameter Abuse80%HIGH
SKILL.md:39
detailhide
Line 39 uses 'find ... -exec rm {} +' with a time-based filter to delete old session files. While the intent is cleanup, this is a dangerous pattern: (1) 'find' combined with 'rm' in a shared directory (~/.gstack/sessions/) could delete files belonging to other concurrent skill invocations, (2) no validation that the files being deleted are actually stale sessions (could be legitimate ongoing sessions), (3) race conditions if two skill instances run simultaneously. The -mmin filter is not atomic—a file could be modified milliseconds before the threshold, causing false deletion.
mkdir -p ~/.gstack/sessions touch ~/.gstack/sessions/"$PPID" _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")fix Replace find+rm with a safer cleanup strategy: (1) use a lock file to serialize session cleanup, (2) validate session files (read PID, check if process is still alive) before deleting, (3) use a session ID (not PPID) and implement explicit session close/cleanup calls, (4) log deletions to a cleanup audit file. Consider using flock(2) for advisory locking.
- 08TM1Tool Parameter Abuse70%HIGH
SKILL.md:73
detailhide
Line 73 removes pending telemetry files without checking if they belong to the current session or a concurrent one. The glob pattern '_PF=$(find ... -name .pending-* ...)' could match files from other skill invocations. The comment says 'pending finalize', implying these are leftover cleanup markers, but removing them without validation could interfere with other concurrent gstack sessions' state management.
if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true fi rm -f "$_PF" 2>/dev/null || true fi break donefix Scope pending-file cleanup to the current SESSION_ID only. Change the pattern to find ~/.gstack/analytics/.pending-"$_SESSION_ID" explicitly. Add validation that the file was created by the current process before removing. Log pending file cleanup with timestamps for audit trails.
- 09TM1Tool Parameter Abuse85%HIGH
SKILL.md:271
detailhide
Line 271 proposes 'git rm -r .claude/skills/gstack/' as an automated action within an AskUserQuestion flow. While user consent is requested, this is extremely destructive: it permanently deletes the entire gstack skill directory from the repo. If a user misunderstands the prompt or accidentally chooses option A, all local gstack customizations, vendored dependencies, and project-specific configurations are lost and committed to git. This is a one-way destructive action that should require explicit confirmation, not a single AskUserQuestion option.
- B) No, I'll handle it myself If A: 1. Run `git rm -r .claude/skills/gstack/` 2. Run `echo '.claude/skills/gstack/' >> .gitignore` 3. Run `~/.claude/skills/gstack/bin/gstack-team-init required` (or `optional`) 4. Run `git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"`fix Add a hard-stop confirmation gate before executing 'git rm -r .claude/skills/gstack/'. Implement a two-stage decision: (1) AskUserQuestion for intent to migrate, (2) if yes, show a summary of what will be deleted with specific file counts and ask for confirmation with explicit typed confirmation (not just yes/no). Offer a backup/archive option before deletion. Commit the deletion in a separate, clearly-labeled commit.
- 10TM1Tool Parameter Abuse65%HIGH
SKILL.md:721
detailhide
Line 721 removes pending analytics files at skill end, but does so unconditionally and without checking if the session-ID matches. If multiple skill instances share the same SESSION_ID (unlikely but possible due to timing collisions), this could delete pending files from concurrent sessions. The cleanup happens after telemetry writes, so the risk is lower than earlier writes, but the pattern of unguarded deletion remains.
```bash _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true # Session timeline: record skill completion (local-only, never sent anywhere) ~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true # Local analytics (gated on telemetry setting)fix Validate SESSION_ID format and add a process-level check before removing pending files. Ensure the pending file's creation timestamp and session ID match the current invocation. Consider using atomic operations (mv + rm) or a session-scoped cleanup that runs only after confirming the session is complete.