Back to skill

Security audit

EMAR adv-plan-diagnosis

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed ad-campaign diagnosis helper that uses configured ad-platform tokens to read campaign data, with some credential-handling and dependency hygiene risks to review.

Install only if you intend the agent to use your Ocean Engine or Tencent Ads API tokens for campaign diagnosis. Keep the .env file restricted, use least-privilege and short-lived tokens, rotate Tencent tokens regularly, and consider pinning dependencies and adding request timeouts before production use.

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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
diagnose.py:106
Finding

Tencent Ads access token transmitted in URL query parameters

Content
View full analysis

Vulnerability Details

File Location: diagnose.py, lines 106-122
Vulnerability Type: Credential exposure through URL query parameters
Risk Level: Medium

Vulnerable Code

python
url = 'https://api.e.qq.com/v1.1/daily_reports/get'
params = {
    'access_token': token,
    'account_id': account_id,
    'level': 'REPORT_LEVEL_ADGROUP',
    'date_range': json.dumps({'start_date': start_date, 'end_date': end_date}),
    'filtering': json.dumps([{'field': 'adgroup_id', 'operator': 'EQUALS', 'values': [str(adgroup_id)]}]),
    'fields': json.dumps(['adgroup_id', 'cost', 'view_count', 'valid_click_count', 'conversions_count']),
    'page': 1,
    'page_size': 10
}
resp = requests.get(url, params=params)

Technical Analysis

The Tencent access token is included in the params dictionary passed to requests.get. The Requests library serializes these parameters into the request URL. Although HTTPS protects the request while it is in transit, query strings are commonly retained by HTTP servers, reverse proxies, network monitoring products, application performance monitoring systems, debugging tools, and exception-reporting systems.

Any component that records the complete URL may therefore persist the access token beyond the execution of the diagnostic command. This increases the credential's exposure compared with transmission through an authorization header.

Attack Path

  1. A user configures a valid TENCENT_ACCESS_TOKEN in the local .env file.
  2. The user invokes Tencent Ads diagnosis.
  3. The script constructs a GET request whose URL contains access_token=<token>.
  4. An API gateway, proxy, monitoring product, debugging system, or remote server records the complete request URL.
  5. A party with unauthorized or overly broad access to those records extracts the token.
  6. The party reuses the token against Tencent Ads APIs before it expires or is revoked.

Exploitation d ...[truncated 527 chars]

Remediation
View remediation

Remediation Suggestions

  1. If supported by the Tencent Ads API, transmit the token in an authorization header rather than the URL:
    python
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.get(url, headers=headers, params=non_secret_params, timeout=(5, 30))
    
  2. If the API contract requires a query parameter, configure application, proxy, gateway, and monitoring logs to redact access_token.
  3. Prevent complete request URLs from appearing in error messages and debug logs.
  4. Grant the token only the minimum scopes required for report retrieval.
  5. Retain tokens only for their necessary lifetime and rotate any token suspected of appearing in logs.
  6. Restrict access to .env and relevant infrastructure logs using filesystem and role-based access controls.

T09 · Insecure Skill Coding Practices

Note
Location
diagnose.py:78
Finding

External HTTP requests lack bounded timeouts

Content
View full analysis

Vulnerability Details

File Location: diagnose.py, lines 78 and 122
Vulnerability Type: Unbounded external network operations
Risk Level: Low

Vulnerable Code

python
resp = requests.get(url, headers=headers, params=params)
resp.raise_for_status()
python
resp = requests.get(url, params=params)
resp.raise_for_status()

Technical Analysis

Neither external API request specifies a timeout. By default, Requests does not impose an overall timeout, so execution may remain blocked indefinitely if a remote endpoint accepts a connection but fails to complete the response.

This is primarily an availability weakness. A slow or malfunctioning remote API, network fault, or connection that deliberately stalls can retain the process and its associated resources. Repeated concurrent invocations can amplify the effect.

Attack Path

  1. A user or automated agent starts an advertising diagnosis.
  2. The script connects to the selected external API.
  3. The remote endpoint or an intermediary delays or stops sending response data without closing the connection.
  4. Because no timeout is configured, the call remains blocked.
  5. Repeated diagnostic invocations accumulate blocked processes or workers, potentially exhausting execution capacity.

Direct exploitation requires influence over the endpoint or network path, or can occur naturally because of an upstream service failure.

Impact Assessment

The issue can delay or prevent diagnostic results and consume process, worker, connection, or memory resources. In a shared or concurrent service, accumulated blocked requests could reduce availability for other users. It does not directly expose credentials, modify data, or grant additional privileges.

Remediation
View remediation

Remediation Suggestions

  1. Apply bounded connect and read timeouts to both requests:
    python
    resp = requests.get(
        url,
        headers=headers,
        params=params,
        timeout=(5, 30),
    )
    
  2. Handle timeout failures explicitly:
    python
    try:
        resp = requests.get(url, params=params, timeout=(5, 30))
        resp.raise_for_status()
    except requests.Timeout:
        raise RuntimeError("The advertising API request timed out")
    
  3. If retries are required, use a small retry limit with exponential backoff and jitter.
  4. Apply an overall execution deadline at the agent or worker level so retries cannot extend execution indefinitely.
  5. Avoid retrying non-idempotent requests automatically; the currently audited requests are GET operations.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Third-party dependencies are not reproducibly pinned

Content
View full analysis

Vulnerability Details

File Location: requirements.txt, lines 1-2
Vulnerability Type: Unbounded dependency resolution and supply-chain exposure
Risk Level: Low

Vulnerable Code

text
requests>=2.25.0
python-dotenv>=1.0.0

Technical Analysis

Both dependencies use only minimum-version constraints and have no upper bounds, lock file, or package hashes. A fresh installation may therefore select a future release that was not reviewed or tested with this project. This makes builds non-reproducible and increases exposure to compromised, malicious, or incompatible future package releases.

The package names observed in the project are legitimate; the audit found no evidence of typosquatting or an intentionally malicious dependency. The risk arises from unconstrained future resolution rather than from a currently identified malicious package.

Attack Path

  1. A future version of an allowed dependency becomes compromised or introduces unsafe behavior.
  2. A user installs the project dependencies after that version is published.
  3. The package resolver selects the affected version because it satisfies the open-ended >= constraint.
  4. Package installation hooks or imported package code execute in the user's environment.
  5. Any resulting impact occurs with the privileges of the user or service installing or running the project.

This path requires compromise or unsafe behavior in a future dependency release; no such release was established during this audit.

Impact Assessment

In a worst-case supply-chain compromise, dependency code could access files, environment variables, API tokens, and network resources available to the Python process. It would execute with the privileges of the installing or running account. More commonly, an incompatible future release could cause application failures or incorrect diagnostics.

Remediation
View remediation

Remediation Suggestions

  1. Pin dependencies to versions that have been reviewed and tested:
    text
    requests==<reviewed-version>
    python-dotenv==<reviewed-version>
    
  2. Generate a lock file or fully resolved requirements file with a dependency-management tool.
  3. Require package hashes during installation, for example with pip's --require-hashes option.
  4. Update dependencies through a controlled review process that includes vulnerability scanning, compatibility tests, and changelog review.
  5. Use a trusted package index and prevent fallback to unapproved package sources.
  6. Regularly rebuild the lock file so security updates can be adopted without returning to unconstrained resolution.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (18)

Tainted flow: 'headers' from os.getenv (line 62, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · diagnose.py (reported line 71)May include surrounding context.

python
"scenes": scenes_str
    }

    resp = requests.get(url, headers=headers, params=params)
    resp.raise_for_status()
    result = resp.json()
    if result.get("code") != 0:

Tainted flow: 'params' from os.getenv (line 101, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The Tencent Ads request places the access token in the URL query parameters, which are more likely to be captured by logs, proxies, browser/history tooling, or monitoring systems than an Authorization header. Although the destination is the intended API, transmitting credentials in the query string increases the chance of accidental credential disclosure.

Content

Scanner excerpt · diagnose.py (reported line 111)May include surrounding context.

python
'page': 1,
        'page_size': 10
    }
    resp = requests.get(url, params=params)
    resp.raise_for_status()
    data = resp.json()
    if data.get('code') != 0:

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The skill explicitly depends on reading access tokens from .env, which is credential access to local secrets. In an agent environment, this is dangerous because a simple user prompt providing account IDs could cause the agent to use stored tokens to access external ad-platform data without robust authorization checks or disclosure.

Content

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

md
巨量引擎使用官方诊断接口;腾讯广告因官方诊断接口下线,使用报表+规则引擎。

两个平台的 access_token 都从 .env 文件读取,需要用户自行配置并定期更新(腾讯 token 有效期2小时)。

若脚本返回 {"status": "error"},将 message 告知用户。

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · diagnose.py (reported line 59)May include surrounding context.

python
def diagnose_ocean_engine(account_id, ad_ids):
    token = os.getenv('OCEAN_ENGINE_ACCESS_TOKEN')
    if not token:
        raise Exception("请在 .env 中配置 OCEAN_ENGINE_ACCESS_TOKEN")

    url = "https://api.oceanengine.com/open_api/v3.0/tools/promotion_diagnosis/suggestion/get/"
    headers = {"Access-Token": token}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · diagnose.py (reported line 98)May include surrounding context.

python
def diagnose_ocean_engine(account_id, ad_ids):
    token = os.getenv('OCEAN_ENGINE_ACCESS_TOKEN')
    if not token:
        raise Exception("请在 .env 中配置 OCEAN_ENGINE_ACCESS_TOKEN")

    url = "https://api.oceanengine.com/open_api/v3.0/tools/promotion_diagnosis/suggestion/get/"
    headers = {"Access-Token": token}

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description lists trigger phrases such as “检查广告”, “计划为什么不起量”, and “成本高怎么办”, which are broad natural-language expressions that could easily appear in normal discussion rather than an intentional skill invocation. The file does not provide limiting context, explicit scope constraints, or negative examples to reduce accidental activation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill instructs the agent to read access tokens from a local .env file and query external advertising platforms, but it does not clearly warn the user that invoking the skill may use locally stored credentials and access account data. This can lead to unintended use of sensitive credentials and silent access to third-party account information under an overly simple diagnostic prompt.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

No manifest is available, so there is no stated purpose that would justify credential access. The code explicitly loads a .env file and later retrieves platform access tokens from environment variables, which is a sensitive capability beyond what can be inferred from an unknown-purpose skill declaration.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · diagnose.py (reported line 61)May include surrounding context.

python
if not token:
        raise Exception("请在 .env 中配置 OCEAN_ENGINE_ACCESS_TOKEN")

    url = "https://api.oceanengine.com/open_api/v3.0/tools/promotion_diagnosis/suggestion/get/"
    headers = {"Access-Token": token}
    promotion_ids_str = json.dumps(ad_ids)
    scenes_str = json.dumps(["CLEAN", "POTENTIAL", "ZOMBIE"])

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

With no manifest available, outbound network access to Ocean Engine is not justified by any declared skill intent. This is a substantive capability because it sends account and promotion identifiers to a third-party API to retrieve diagnosis data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The Ocean Engine request sends account and promotion identifiers externally without any explicit user-facing disclosure. While this is part of the intended integration and uses HTTPS to the official endpoint, the lack of transparency is still a security/privacy weakness in an agent-skill setting.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · diagnose.py (reported line 100)May include surrounding context.

python
if not token:
        raise Exception("请在 .env 中配置 TENCENT_ACCESS_TOKEN")

    url = 'https://api.e.qq.com/v1.1/daily_reports/get'
    params = {
        'access_token': token,
        'account_id': account_id,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This skill sends account identifiers, ad-group filters, reporting ranges, and an access token to Tencent Ads without any visible disclosure, consent flow, or declared scope controls. In an agent-skill context, silent outbound transmission of business data and credentials is dangerous because users may invoke the skill without understanding what leaves the environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code transmits a Tencent Ads access token with no user-facing warning or disclosure and does so in request parameters, increasing the risk of unintentional credential leakage. In a reusable skill, hidden credential use undermines informed consent and makes accidental exposure through network logs more likely.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower bound only, which allows different and potentially vulnerable versions to be installed over time. This weakens build reproducibility and makes it impossible to verify whether a safe version of requests will actually be used in deployment.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.25.0
python-dotenv>=1.0.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The manifest references requests without pinning an exact version, while the package has multiple known advisories across versions. Because the installed version is not fixed, the environment could resolve to an affected release, leaving exposure to known issues such as credential leakage or other historical vulnerabilities.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is not pinned to an exact version, so installations may resolve to different releases depending on when and where the skill is installed. This creates supply-chain risk and prevents reliable confirmation that a non-vulnerable python-dotenv version is in use.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
requests>=2.25.0
python-dotenv>=1.0.0

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
85% confidence
Finding

The manifest includes python-dotenv without an exact version pin despite known advisories affecting some releases. Without a fixed version, there is no assurance that deployments will avoid vulnerable builds, particularly where dotenv file handling could interact with local files or symlinks.

Content

No source excerpt is available for this finding.