T09 · Insecure Skill Coding Practices
- Location
SKILL.md:17- Finding
Shared Bearer Token Can Be Sent to Unrestricted or Plaintext Endpoint URLs
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed automation guide for turning prioritized tickets into draft PRs, with important setup risks around tokens, endpoints, and browser QA profiles.
Install only if you are prepared to provide dedicated least-privilege forge and agent tokens, configure the four endpoints to trusted HTTPS origins, keep secrets outside the workspace, and use only a dedicated test browser profile against preview/test data. Review the retention cron setup before enabling browser QA because screenshots may contain authenticated session data.
SKILL.md:17Shared Bearer Token Can Be Sent to Unrestricted or Plaintext Endpoint URLs
The declared description promises a ticket-to-draft-PR automation agent. The supplied code does something materially different: it is a standalone local validation script for a brief/prompt payload, enforcing a mandated prefix, minimum/target prompt lengths, and required JSON fields before emitting a JSON object to stdout. It explicitly never performs network calls and contains no logic for reading ticket queues, creating PRs, reviewing code, or ensuring non-merge behavior. This is a clear description-behavior mismatch.
The declared purpose describes an automation agent for converting ticket queues into reviewed draft pull requests. The supplied code chunk does something materially different: it enforces retention policies on local repository data. Specifically, it consumes pre-fetched PR state JSON, removes stale entries from memory/qa-index.json, memory/remediation-index.json, and memory/pr-index.json, and deletes screenshot/run directories under work/qa-runs for closed or aged PRs. This is not a supporting implementation detail of PR drafting; it is a distinct maintenance/cleanup function with a different primary purpose, different resources, and different operational context. Therefore the description does not accurately represent the code.
The skill declares no explicit tool/permission scope despite instructing use of shell, environment variables, file reads/writes, git, gh, curl, and python3. In an agent platform, missing scope boundaries can cause the runtime to grant broader capabilities than intended, increasing the blast radius if the skill is misused or prompt-injected.
The skill explicitly sends ticket data, PR URLs, and in one path the full grounded brief off-machine via configurable URLs. Even though the document discloses this and makes it opt-in, it still creates a real data exfiltration path that could leak sensitive source context, internal ticket content, or metadata if the endpoints are misconfigured, compromised, or pointed at untrusted infrastructure.
| 4 | definition non-empty | acceptance criteria + explicit out-of-scope | client + server |
| — | Unverifiable anchor | no ack — the card stays in the grounding queue, alert a human | agent rule |
Duplicate the gate on purpose. Locally you fail before the network call; server-side because your endpoint must never depend on the politeness of its client — a retry script or a hand-written curl will send garbage eventually. Configure the prefix first. ${TARGET_REPO} is a placeholder: export BRIEF_GATE_PREFIX with your repo name substituted, byte-identical to the string your server checks. The script refuses to run on a placeholder — or on an empty value, since startswith("") matches every prompt and would report a disabled gate as a passed one.
export BRIEF_GATE_PREFIX="Read CLAUDE.md AND AGENTS.md at the root of app-example first"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
For each final STALE:
curl -fsS -X POST "${STALE_ACK_URL}" -H "Authorization: Bearer ${AGENT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"card_id":"tkt-401","reason":"anchor file absent: src/lib/invoice-filter.ts","commit":"9f2c1ab"}'
# Output: {"ok":true,"action":"auto_flipped"} → the grounding link will re-enrich it
No suspicious patterns detected.