Back to skill

Security audit

TGA Analyze

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says: it logs in to TGA and downloads reports, but it handles credentials and cached tokens that users must protect carefully.

Install only if you trust this skill with your TGA credentials, browser cookies, cached token, and downloaded report data. Keep .env and .tga-token out of source control and shared folders, restrict their file permissions, delete the cached token when finished, and run the login/download commands only for TGA reports you intend to export.

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

Warning
Location
scripts/tga.js:76
Finding

Authentication Token Cached Without Restrictive File Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/tga.js, lines 76–79
Vulnerability Type: Plaintext sensitive credential stored with process-default permissions
Risk Level: Medium

Vulnerable Code

javascript
function saveToken(token) {
  fs.writeFileSync(TOKEN_PATH, JSON.stringify({ token }, null, 0), 'utf8');
  console.log('Token 已写入:', TOKEN_PATH);
}

Technical Analysis

The Skill stores the TGA bearer token in .tga-token as plaintext without explicitly setting restrictive file permissions. fs.writeFileSync therefore relies on the process umask when creating the file and preserves the permissions of an existing file when overwriting it.

On systems with a permissive umask, an insecure preexisting .tga-token, shared accounts, or broadly accessible Skill directories, another local user or process may be able to read the token. Because the token is subsequently accepted as an authorization credential by TGA APIs, possession may allow API access without knowing the login name, encrypted password, or browser cookies.

This token cache supports the documented workflow, but leaving its access controls to the execution environment exceeds the minimum safe privilege exposure necessary for caching.

Attack Path

  1. The legitimate user runs node scripts/tga.js login.
  2. The script obtains a valid TGA access token and writes it to .tga-token.
  3. The resulting file is readable by another local user or compromised process because of a permissive umask, directory permissions, or preexisting file mode.
  4. The attacker reads and parses the plaintext token.
  5. The attacker submits the token to the TGA APIs before it expires or is revoked.
  6. API operations execute with the permissions associated with the victim's TGA session.

Impact Assessment

Successful exploitation may expose TGA projects and downloadable reports available to the authenticated account. The attacker could potentially ...[truncated 397 chars]

Remediation
View remediation

Remediation Suggestions

  • Create the token file with owner-only permissions:

    javascript
    fs.writeFileSync(
      TOKEN_PATH,
      JSON.stringify({ token }),
      { encoding: 'utf8', mode: 0o600 }
    );
    
  • Because the creation mode does not repair an insecure existing file, explicitly enforce permissions after writing:

    javascript
    fs.chmodSync(TOKEN_PATH, 0o600);
    
  • Use an atomic replacement strategy with a temporary file created as 0o600, then rename it into place. Ensure the temporary file is created in a private directory.

  • Verify that the Skill directory is not writable or readable by unrelated local users.

  • Prefer an operating-system credential store or secret-management service instead of a plaintext JSON file.

  • Delete the cached token when it is invalidated and support explicit logout or token revocation.

  • Avoid printing token values or file contents in logs.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tga.js:302
Finding

Bearer Token Included in Report Download URL

Content
View full analysis

Vulnerability Details

File Location: scripts/tga.js, lines 302–314
Vulnerability Type: Sensitive authentication token transmitted in a URL query parameter
Risk Level: Medium

Vulnerable Code

javascript
const downloadPath = `/v1/ta/auth/manage/task/taskFileDownload?access_token=${encodeURIComponent(token)}&projectId=${projectId}&taskId=${taskId}`;
const downloadHeaders = {
  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
  'accept-language': 'zh-CN,zh;q=0.9',
  'cache-control': 'no-cache',
  'cookie': env.TGA_COOKIES,
  'pragma': 'no-cache',
  'priority': 'u=0, i',
  'referer': BASE + '/',
  'sec-ch-ua': '"Not:A-Brand";v="99", "Google Chrome";v="145", "Chromium";v="145"',
  'sec-ch-ua-mobile': '?0',
  'sec-ch-ua-platform': '"macOS"',

Technical Analysis

The report-download request places the bearer token in the access_token query parameter. Although the request is sent over HTTPS to the fixed TGA origin, TLS only protects the request while in transit. Query strings can still be recorded by the destination server, reverse proxies, API gateways, monitoring platforms, tracing systems, error reports, or other infrastructure with access to request metadata.

URL encoding prevents malformed query syntax but does not conceal the token. Any party that can read a retained URL may recover and replay the credential while it remains valid.

Authentication is necessary for the declared report-download function. However, using a reusable bearer credential in the URL creates avoidable exposure if the endpoint supports authorization headers or can issue a narrower, short-lived download credential.

Attack Path

  1. The authenticated user invokes the report download command.
  2. The script constructs a URL containing the reusable TGA access token.
  3. A server, proxy, gateway, tracing ...[truncated 875 chars]
Remediation
View remediation

Remediation Suggestions

  • If supported by the TGA endpoint, remove access_token from the URL and send it in the authorization header:

    javascript
    const downloadPath =
      `/v1/ta/auth/manage/task/taskFileDownload?projectId=${encodeURIComponent(projectId)}&taskId=${encodeURIComponent(taskId)}`;
    
    const downloadHeaders = {
      ...existingHeaders,
      authorization: `Bearer ${token}`,
    };
    
  • If the service requires a URL credential, request a single-use, short-lived, task-specific download token rather than placing the general API bearer token in the query string.

  • Configure servers, proxies, gateways, observability systems, and error reporting tools to redact access_token and other authentication parameters.

  • Minimize token lifetime and scope, rotate credentials after suspected exposure, and provide server-side revocation.

  • Ensure errors and debug logs never print complete request URLs containing credentials.

  • URL-encode projectId and taskId independently when building query parameters, or construct the query with URLSearchParams.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description says it will parse URLs, unzip archives, and analyze XLSX files, but the documented implementation actually centers on credential handling, token caching, and a download script, while key claimed behaviors are absent or delegated manually. This mismatch is dangerous because users and orchestration layers may trust the declared purpose while overlooking sensitive auth handling and local persistence of tokens, leading to under-informed consent and overly broad activation.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 48)May include surrounding context.

md
登录与下载由脚本完成,无需手写 curl。脚本位于本技能目录下 `scripts/tga.js`,读取同目录的 `.env` 与 `.tga-token`。

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The script is explicitly designed to consume credentials from a local .env file and persistent token file, which creates a credential-handling surface inside the skill. In an agent-skill context, reading local secrets and using them for outbound authentication is sensitive because it can enable unauthorized access or exfiltration if the skill is invoked unexpectedly or the workspace is shared.

Content

Scanner excerpt · scripts/tga.js (reported line 3)May include surrounding context.

js
#!/usr/bin/env node
/**
 * TGA 登录与下载脚本。从本技能目录读取 .env 与 .tga-token。
 * 用法:
 *   node tga.js login
 *   node tga.js download <projectId> <dashboardId> [outputDir] [--task-id=<id>]

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The hard-coded paths to .env and .tga-token indicate the skill will read and persist authentication material within its directory. Persisting bearer tokens on disk increases the blast radius of compromise because anyone or any process with access to the directory may reuse the token to access TGA resources.

Content

Scanner excerpt · scripts/tga.js (reported line 15)May include surrounding context.

js
const https = require('https');

const SKILL_DIR = path.resolve(__dirname, '..');
const ENV_PATH = path.join(SKILL_DIR, '.env');
const TOKEN_PATH = path.join(SKILL_DIR, '.tga-token');

const BASE = 'https://tga-web.hortorgames.com';

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

loadEnv() reads raw secrets from .env, including login name, encoded password, and cookies, making the skill capable of harvesting and using credentials from local storage. In this skill's context, that is more dangerous than a generic config read because the same secrets are immediately used for authenticated API access to a third-party system.

Content

Scanner excerpt · scripts/tga.js (reported line 39)May include surrounding context.

js
function loadEnv() {
  if (!fs.existsSync(ENV_PATH)) {
    console.error('缺少 .env 文件,路径:', ENV_PATH);
    process.exit(1);
  }
  const raw = fs.readFileSync(ENV_PATH, 'utf8');

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

The required variables include username, encrypted password, and cookies, which together are powerful authentication artifacts. Combining multiple auth factors in one plaintext file materially increases risk of account takeover if the file is exposed, copied, or included in backups/logs.

Content

Scanner excerpt · scripts/tga.js (reported line 57)May include surrounding context.

js
}
  for (const k of ['TGA_LOGIN_NAME', 'TGA_ENCRYPTED_PASSWORD', 'TGA_COOKIES']) {
    if (!env[k]) {
      console.error('.env 中缺少:', k);
      process.exit(1);
    }
  }

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The login flow takes local credentials and transmits them to obtain an access token, then persists that token for later reuse. In an agent skill, this expands the trust boundary significantly: anyone able to trigger the skill may cause secret use and create a reusable token on disk, enabling access beyond the original session.

Content

Scanner excerpt · scripts/tga.js (reported line 114)May include surrounding context.

js
async function login() {
  const env = loadEnv();
  // 与 curl --data-raw 一致:body 原样发送。enPassword 在 .env 里已是前端/浏览器给出的编码值(含 %2B、%3D 等),不可再用 URLSearchParams 二次编码,否则 % 会变成 %25 导致登录失败
  const body = `loginName=${encodeURIComponent(env.TGA_LOGIN_NAME)}&enPassword=${env.TGA_ENCRYPTED_PASSWORD}&locale=zh_CN`;

  // 与 example.md 登录 curl 完全一致:全部 header + -b cookie

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill directs use of both shell and network-capable actions (node ... login, download, file writes, unzip) but does not declare explicit tool scope or permissions. This is dangerous because an agent may invoke powerful side-effecting operations without clear sandboxing or user-visible authorization boundaries, increasing the risk of unintended credential use, downloads, and filesystem modification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation text includes broad phrases like analyzing current TGA webpage data or TGA data, which could match ordinary user requests too loosely. In a skill that performs login, token reuse, remote downloads, and local file writes, overbroad triggering is risky because it can cause sensitive side effects in contexts where the user did not explicitly request authentication or data export.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The markdown instructs the skill to read credentials from .env, use cookies, cache tokens locally, download report ZIPs, and write extracted files, but provides no explicit privacy or side-effect warning. This is dangerous because it normalizes handling sensitive authentication material and potentially sensitive report data without foregrounding local persistence, exposure risk, retention, or the need for user consent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/tga.js (reported line 114)May include surrounding context.

js
async function login() {
  const env = loadEnv();
  // 与 curl --data-raw 一致:body 原样发送。enPassword 在 .env 里已是前端/浏览器给出的编码值(含 %2B、%3D 等),不可再用 URLSearchParams 二次编码,否则 % 会变成 %25 导致登录失败
  const body = `loginName=${encodeURIComponent(env.TGA_LOGIN_NAME)}&enPassword=${env.TGA_ENCRYPTED_PASSWORD}&locale=zh_CN`;

  // 与 example.md 登录 curl 完全一致:全部 header + -b cookie

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The login request forces locale=zh_CN, and the script also hard-codes Chinese language headers elsewhere, which imposes a specific locale without offering the user any opt-in or configuration choice. This matches the policy category for language/locale violations because the behavior is embedded directly in the skill rather than documented as a region-specific requirement.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.