Back to skill

Security audit

ai-news-pipeline-new

Security checks for vulnerabilities and agentic risk

Overview

This news-reporting skill mostly matches its purpose, but it has review-worthy risks around external API credentials, untrusted RSS content, and generated spreadsheets.

Install only in a dedicated workspace, use trusted HTTPS RSS sources, avoid feed credentials on plaintext URLs, set ARK_API_BASE only to a trusted model provider, consider using --disable-ai for sensitive content, and treat generated XLSX files as untrusted until formula escaping is added.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_company_report.py:497
Finding
Domestic report permits spreadsheet formula injection from RSS content## Vulnerability Details **File Location**: `scripts/generate_company_report.py:497-500` **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: High ### Vulnerable Code ```python for row in merged_rows: worksheet.append([row.get(header, "") for header in headers]) ``` ### Technical Analysis The report writer inserts externally sourced RSS fields directly into XLSX cells. These fields include the title, article content, source, timestamp, and link. No neutralization is applied when a value begins with a spreadsheet formula marker such as `=`, `+`, `-`, or `@`. Spreadsheet software may interpret such values as formulas rather than text. Depending on the software and its security settings, a formula can initiate external network requests, expose report data through attacker-controlled URLs, present deceptive hyperlinks, or invoke dangerous legacy spreadsheet functionality. ### Attack Path 1. An attacker publishes an RSS item containing a formula payload in its title, content, source, or link. 2. The configured feed collector stores the malicious value in a JSONL data file. 3. `generate_company_report.py` matches the item to a monitored company. 4. The value is passed unchanged to `worksheet.append`. 5. A user opens `reports/company_mentions.xlsx`. 6. The spreadsheet application evaluates or presents the injected formula according to its security configuration. ### Impact Assessment Exploitation does not directly grant Python-process privileges. It targets the user opening the generated workbook and can compromise report integrity, cause unintended outbound requests, disclose information included in formula arguments, or potentially trigger spreadsheet-specific code-execution features in vulnerable or permissively configured clients.
Remediation
## Remediation Suggestions - Treat every feed-derived value as untrusted before writing it to XLSX. - Prefix values beginning with `=`, `+`, `-`, or `@` with a single quote. - Explicitly assign sanitized values as string cells rather than relying on automatic type detection. - Apply the same sanitization to existing workbook rows before rewriting cumulative reports. - Add tests covering formula-prefixed titles, content, links, source names, and AI-generated fields. Example hardening: ```python def safe_excel_text(value: object) -> str: text = str(value or "") if text.startswith(("=", "+", "-", "@")): return "'" + text return text for row in merged_rows: worksheet.append([safe_excel_text(row.get(header, "")) for header in headers]) ```

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_international_report.py:490
Finding
International report permits spreadsheet formula injection from RSS content## Vulnerability Details **File Location**: `scripts/generate_international_report.py:490-493` **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: High ### Vulnerable Code ```python for row in merged_rows: worksheet.append([row.get(header, "") for header in headers]) ``` ### Technical Analysis International RSS fields are written directly into spreadsheet cells without protection against formula interpretation. Attacker-controlled values beginning with spreadsheet control characters can therefore be stored as formulas in `international_company_mentions.xlsx`. The cumulative merge does not eliminate the issue: both new feed values and values loaded from an existing workbook are written back without sanitization. ### Attack Path 1. An attacker places a formula-prefixed value in an international RSS item. 2. The item passes the international relevance filter and is stored in JSONL. 3. The report generator converts the record into a report row. 4. The row is appended to the workbook without escaping. 5. A report recipient opens the generated workbook. 6. The spreadsheet application processes the attacker-controlled formula. ### Impact Assessment The principal impact is against the report recipient rather than the Skill process. It includes report manipulation, unintended network callbacks, possible disclosure of data encoded into formula requests, deceptive content, and exposure to client-specific spreadsheet execution behavior.
Remediation
## Remediation Suggestions - Sanitize every untrusted value before writing it to a cell. - Escape values beginning with `=`, `+`, `-`, or `@`. - Apply sanitization to RSS fields, model output, and rows loaded from previous reports. - Where possible, set the cell data type explicitly to text. - Add regression tests that inspect generated XLSX cell types and values. Example: ```python def safe_excel_text(value: object) -> str: text = str(value or "") return "'" + text if text.startswith(("=", "+", "-", "@")) else text ```

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_company_report.py:271
Finding
Domestic RSS content is embedded directly into model instructions## Vulnerability Details **File Location**: `scripts/generate_company_report.py:271-277` **Vulnerability Type**: Indirect prompt injection **Risk Level**: Medium ### Vulnerable Code ```python "\n\n" f"Enterprise name: {row['Enterprise name']}\n" f"Original title: {row['News title']}\n" f"News content: {row['News content']}\n" f"News source: {row['News source']}\n" f"News time: {row['News time']}\n" f"News link: {row['News link']}\n" ``` The actual source uses Chinese field labels, but the security-relevant operation is the direct interpolation of the corresponding row fields shown above. ### Technical Analysis Untrusted feed content is concatenated into the same prompt string as the model’s operational instructions. The prompt does not clearly delimit the article as inert data or instruct the model to disregard commands contained in the article. A malicious publisher can include text such as instructions to ignore the requested JSON policy, fabricate a summary, promote a particular entity, or misrepresent the article. JSON parsing constrains the response format but does not ensure that the generated values faithfully summarize the source. ### Attack Path 1. An attacker publishes an RSS article containing model-directed instructions. 2. The collector stores the text without removing instruction-like content. 3. The article matches a company alias and is selected for AI enrichment. 4. The malicious article text is inserted directly into the model prompt. 5. The model follows some or all embedded instructions. 6. Manipulated titles or summaries are written into the XLSX and DOCX reports. ### Impact Assessment This issue affects report integrity and trustworthiness. It can cause false, biased, promotional, or misleading summaries to enter business reports. The model call has no tool or local-file access, so the demonstrated path does not provide operating-system privileges or arbitrary local code executio ...[truncated 2 chars]
Remediation
## Remediation Suggestions - Put untrusted article fields in a clearly delimited data section. - Add an explicit instruction that commands appearing inside source content are untrusted and must never modify the summarization task. - Use separate system and user message roles if the model API supports them. - Prefer a structured input object over free-form prompt concatenation. - Validate whether generated claims are supported by the original article. - Flag anomalous output rather than silently inserting it into final reports. - Add adversarial tests containing common prompt-injection phrases.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_international_report.py:221
Finding
International RSS content can manipulate summaries and impact rankings through prompt injection## Vulnerability Details **File Location**: `scripts/generate_international_report.py:221-227` **Vulnerability Type**: Indirect prompt injection **Risk Level**: Medium ### Vulnerable Code ```python f"{retry_hint}\n" f"Original title: {row['News title']}\n" f"News content: {row['News content']}\n" f"News source: {row['News source']}\n" f"News time: {row['News time']}\n" f"News link: {row['News link']}\n" ``` The actual source uses Chinese field labels, but the security-relevant operation is the direct interpolation of these untrusted row values. ### Technical Analysis International feed data is placed directly into the model prompt alongside instructions for generating a title, summary, and `impact_score`. There is no robust trust-boundary marker between application instructions and article content. This is especially significant because the generated impact score controls sorting and determines which five international items appear in the Word brief. An attacker can attempt to instruct the model to assign an artificially high score or produce promotional text. The retry mechanism repeats the same attacker-controlled content up to three times and does not address the trust-boundary problem. ### Attack Path 1. An attacker publishes an AI-related RSS item containing prompt-injection instructions. 2. The item satisfies the topic and event filters. 3. Its title and content are embedded in the AI request. 4. The model returns attacker-influenced JSON, including a high `impact_score`. 5. The score is accepted as long as it parses as an integer and is then clamped to the range 0–100. 6. Sorting prioritizes the manipulated item, potentially placing it in the top-five international section of the Word brief. ### Impact Assessment An attacker can influence report content, prioritization, and editorial conclusions. This can displace legitimate stories from the brief or insert misleading claims. The issue does not d ...[truncated 126 chars]
Remediation
## Remediation Suggestions - Clearly label feed fields as untrusted quoted data. - Explicitly instruct the model not to follow instructions found in article content. - Separate model instructions from source data using structured roles or API-native structured input. - Calculate ranking from deterministic metadata where possible instead of relying exclusively on model output. - Validate unusually high scores through independent rules or a second verification step. - Detect instruction-like phrases in source material and flag affected records for review. - Ensure retries do not repeat untrusted input without additional defensive framing.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/collect_feeds.py:218
Finding
RSS Basic Authentication credentials may be transmitted without transport protection## Vulnerability Details **File Location**: `scripts/collect_feeds.py:218-230` **Vulnerability Type**: Insecure credential transport **Risk Level**: Medium ### Vulnerable Code ```python def build_request(source: SourceConfig) -> Request: headers = {"User-Agent": USER_AGENT} if source.headers: headers.update(source.headers) if source.username and source.password: basic_token = base64.b64encode( f"{source.username}:{source.password}".encode("utf-8") ).decode("ascii") headers["Authorization"] = f"Basic {basic_token}" return Request(source.url, headers=headers) def fetch_feed(source: SourceConfig) -> bytes: request = build_request(source) with urlopen(request, timeout=30) as response: return response.read() ``` ### Technical Analysis Base64 encoding is the normal representation for HTTP Basic Authentication, but it does not encrypt credentials. The code accepts arbitrary source URLs and does not require HTTPS when a username and password are configured. Consequently, an authenticated feed configured with an `http://` URL transmits recoverable credentials over plaintext transport. Redirect destinations are also not explicitly restricted by application logic, so authenticated redirect behavior should be hardened rather than delegated entirely to default URL handling. The encoded token is not printed or written to local output. The issue is network transport, not stdout exfiltration. ### Attack Path 1. A feed is configured with `username`, `password`, and an HTTP URL, whether through mistake or malicious configuration. 2. The collector Base64-encodes `username:password`. 3. It places the result in the `Authorization` header. 4. `urlopen` sends the request over an unencrypted connection. 5. A network-positioned attacker captures the header and decodes the credentials. ### Impact Assessment The exposed privileges are th ...[truncated 218 chars]
Remediation
## Remediation Suggestions - Reject authenticated feed URLs unless their scheme is HTTPS. - Parse and validate URLs before constructing the request. - Reject redirects from HTTPS to HTTP. - Strip authorization headers on cross-origin redirects. - Consider restricting redirects entirely for authenticated feeds. - Avoid accepting an `Authorization` value through arbitrary user-supplied headers when dedicated credential fields are used. - Document that Basic Authentication is safe only when protected by TLS. Example validation: ```python from urllib.parse import urlparse parsed = urlparse(source.url) if source.username or source.password: if parsed.scheme.lower() != "https": raise ValueError("Authenticated RSS sources must use HTTPS") ```

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_company_report.py:343
Finding
Domestic model API key can be disclosed to an unrestricted endpoint override## Vulnerability Details **File Location**: `scripts/generate_company_report.py:343-352` **Vulnerability Type**: Configurable credential exfiltration destination **Risk Level**: Medium ### Vulnerable Code ```python request = Request( f"{ARK_API_BASE.rstrip('/')}/responses", data=body, headers={ "Content-Type": "application/json; charset=utf-8", "Authorization": f"Bearer {ARK_API_KEY}", }, method="POST", ) with urlopen(request, timeout=ARK_TIMEOUT_SECONDS) as response: response_payload = json.loads(response.read().decode("utf-8")) ``` The destination is initialized from an unrestricted environment variable: ```python ARK_API_BASE = os.getenv( "ARK_API_BASE", "https://ark.cn-beijing.volces.com/api/v3", ) ``` ### Technical Analysis The default endpoint is consistent with the declared Volcengine integration. However, `ARK_API_BASE` can be set to any URL, and the application then sends both the Bearer API key and complete feed-derived prompt to that destination. The code does not enforce HTTPS or verify that the hostname belongs to the intended provider. This creates a credential-disclosure path in environments where deployment variables, task configuration, wrapper scripts, or inherited environment settings can be manipulated. ### Attack Path 1. An attacker or unsafe deployment configuration sets `ARK_API_BASE` to an attacker-controlled URL. 2. A report run starts with a valid `ARK_API_KEY`. 3. The application constructs a POST request to the attacker URL. 4. The request includes the API key in the `Authorization` header. 5. The request body also contains company names and collected news content. 6. The attacker records the key and submitted report data. ### Impact Assessment The attacker obtains the privileges and quota associated with `ARK_API_KEY` and receives all article data submitted for domestic report generation. No arbitrary wo ...[truncated 40 chars]
Remediation
## Remediation Suggestions - Require the endpoint scheme to be HTTPS. - Allowlist the expected Volcengine hostname or a documented set of trusted endpoints. - Fail closed when the endpoint cannot be validated. - If custom providers are necessary, require a separate provider-specific credential rather than automatically forwarding `ARK_API_KEY`. - Avoid following cross-origin redirects with the Bearer header. - Log only the validated hostname, never the API key. - Document the exact data fields sent to the model provider.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_international_report.py:285
Finding
International model API key can be disclosed to an unrestricted endpoint override## Vulnerability Details **File Location**: `scripts/generate_international_report.py:285-294` **Vulnerability Type**: Configurable credential exfiltration destination **Risk Level**: Medium ### Vulnerable Code ```python request = Request( f"{ARK_API_BASE.rstrip('/')}/responses", data=body, headers={ "Content-Type": "application/json; charset=utf-8", "Authorization": f"Bearer {ARK_API_KEY}", }, method="POST", ) with urlopen(request, timeout=ARK_TIMEOUT_SECONDS) as response: response_payload = json.loads(response.read().decode("utf-8")) ``` The destination is controlled by: ```python ARK_API_BASE = os.getenv( "ARK_API_BASE", "https://ark.cn-beijing.volces.com/api/v3", ) ``` ### Technical Analysis Any environment-provided API base receives the Volcengine Bearer key and international article data. No application-level scheme or hostname restriction ensures that the destination is the intended provider. Although using a configurable compatible endpoint may be operationally useful, automatically pairing that endpoint with the same secret exceeds a safe least-privilege design unless the destination is explicitly trusted. ### Attack Path 1. `ARK_API_BASE` is changed to a malicious or unintended endpoint. 2. International report generation starts with `ARK_API_KEY` configured. 3. For each selected article, the code posts the prompt to that endpoint. 4. The malicious server captures the Bearer key, article title, article content, source, time, and link. 5. Retries can transmit the same data multiple times. ### Impact Assessment The attacker can misuse the model API credential within its assigned permissions and quota. The attacker also obtains international report input. The implementation does not use this route to upload arbitrary files from the workspace.
Remediation
## Remediation Suggestions - Enforce HTTPS and validate the destination hostname. - Allowlist the intended model provider. - Disable cross-origin redirects for authenticated requests. - Use separate credentials for separately configured providers. - Require an explicit opt-in for custom endpoints. - Provide a `--disable-ai` default in untrusted deployment environments until endpoint validation succeeds.

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:1
Finding
Third-party dependencies are installed without version or integrity constraints## Vulnerability Details **File Location**: `scripts/requirements.txt:1-2` **Vulnerability Type**: Unpinned dependency supply-chain risk **Risk Level**: Medium ### Vulnerable Code ```text openpyxl python-docx ``` ### Technical Analysis Both dependencies are specified without exact versions or package hashes. Each installation therefore resolves whatever versions the configured package index currently serves. This makes deployments non-reproducible and prevents integrity verification. A compromised package release, compromised package index, or unsafe index configuration could cause malicious code to execute during installation or when the package is imported. No evidence was found that the named dependencies are themselves malicious; the vulnerability is the absence of version and integrity controls. ### Attack Path 1. A dependency release or configured Python package index is compromised. 2. A user follows the documented `pip install -r scripts/requirements.txt` command. 3. Pip resolves the unrestricted dependency to the compromised distribution. 4. Malicious package code executes during installation or subsequent import. 5. The code runs with the privileges of the user operating the Skill. ### Impact Assessment Successful supply-chain compromise can obtain all permissions available to the installing or executing user, including access to the workspace, environment variables such as `ARK_API_KEY`, generated reports, and network connectivity.
Remediation
## Remediation Suggestions - Pin every direct dependency to a reviewed exact version. - Generate and verify cryptographic hashes using a lockfile or `--require-hashes`. - Review and pin transitive dependencies as well. - Install packages only from a trusted package index. - Use automated dependency scanning and controlled update review. - Build in an isolated environment with minimal privileges. Example structure: ```text openpyxl==REVIEWED_VERSION --hash=sha256:REVIEWED_HASH python-docx==REVIEWED_VERSION --hash=sha256:REVIEWED_HASH ```
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (26)

Tainted flow: 'request' from os.getenv (line 342, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method="POST",
    )

    with urlopen(request, timeout=ARK_TIMEOUT_SECONDS) as response:
        response_payload = json.loads(response.read().decode("utf-8"))

    text = extract_text_from_response(response_payload)
Confidence
90% confidence
Finding
The HTTP destination is derived from ARK_API_BASE in the environment and used directly for an authenticated outbound request carrying the Bearer token and article content. If an attacker can influence environment variables in the agent/workspace runtime, they can redirect requests to a malicious endpoint, exfiltrating the API key and potentially sensitive news content; in this skill context, automatic report generation makes such silent exfiltration more plausible.

Tainted flow: 'request' from os.getenv (line 284, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method="POST",
    )

    with urlopen(request, timeout=ARK_TIMEOUT_SECONDS) as response:
        response_payload = json.loads(response.read().decode("utf-8"))

    text = extract_text_from_response(response_payload)
Confidence
91% confidence
Finding
The script constructs an outbound HTTP request using ARK_API_BASE and ARK_API_KEY from environment variables and sends full news content to that endpoint. Because the base URL is externally configurable, a compromised workspace or wrapper could redirect requests and exfiltrate data and bearer credentials to an attacker-controlled server; in this skill's 'self-contained workspace' context, the hidden external call makes the risk more significant.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description promises a self-contained AI news workflow covering Chinese and international news, including optional high-frequency RSS capture, scheduled report delivery, cumulative Excel outputs, and a merged Word brief. The supplied code chunk is much narrower: it loads rows from existing Excel files, filters them by date/time window, selects top international items, and writes a formatted .docx brief. It does not fetch RSS feeds, schedule jobs, deliver reports, or create/update Excel outputs. The Word brief functionality is consistent with part of the description, but the actual code does not represent the broader declared workflow and instead implements only one downstream report-writing component.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code clearly supports part of the description: it is self-contained in the current workspace, reads domestic/international source configs, collects RSS/Atom items, and stores cumulative local outputs with deduplication and logging. However, the declared purpose promises a broader workflow including scheduled report delivery, cumulative Excel outputs, and a merged Word brief. None of those capabilities appear in this code chunk. The actual behavior is limited to network feed retrieval, filtering, state tracking, and JSONL persistence. Because major declared outputs and delivery/reporting functions are absent, the description does not accurately represent what this supplied code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code chunk is a report-generation component, not a full end-to-end news workflow. It reads existing local JSONL data files, filters/matches articles against companies.txt, optionally enriches matches via an external ARK model API, writes a cumulative Excel workbook, and creates a Word brief with imported international rows. The declared description promises a self-contained Chinese/international AI news workflow with modes for RSS capture-only or scheduled report delivery-only, but this script contains neither RSS ingestion nor scheduling/delivery logic. The external ARK API dependency also conflicts with the 'self-contained' characterization. While cumulative Excel output and a merged Word brief are partially consistent, the overall declared purpose materially overstates and mischaracterizes what this code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The declared description covers a fairly broad self-contained AI news workflow with multiple operating modes and report-generation outputs. The supplied code chunk is a narrow wrapper script for capture-only execution: it accepts a workspace path, sets an environment variable, and delegates to collect_feeds.main(). That aligns with only one slice of the declared behavior (RSS capture only), but not the full described workflow including scheduled delivery and document outputs. Because the description presents capabilities materially broader than what this code chunk actually performs, this is a description-behavior mismatch for the provided code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The code in run_full_workflow.py is an orchestrator that always performs both steps: feed collection and report building. The description says the skill should be used when the user wants either high-frequency RSS capture only or scheduled report delivery only, which implies selective single-mode operation; this script does not provide such branching and instead always runs the full workflow. It does align with using the current workspace and not an external repository path, and the optional time-window/disable-AI arguments are consistent with report generation support. However, the primary purpose as implemented is a full end-to-end runner, not the narrower 'capture only or report only' behavior described. Also, while downstream scripts may create Excel or Word outputs, that is not established by this supplied code chunk itself.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description covers a broader end-to-end AI news workflow with two possible operating modes: RSS capture only or scheduled report delivery only, plus cumulative Excel outputs and a merged Word brief. The supplied code chunk is specifically a 'report only' runner. It sets the workspace, derives a time window, and calls two report-generation modules for China and international reports. There is no RSS capture logic in this chunk, and the primary purpose is narrower than the declared description. While the script is consistent with the self-contained/current-workspace and merged Word brief aspects, the missing capture-only mode and narrower scope make the description inaccurate for this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description describes a complete AI news workflow with capture, reporting, and document generation. The supplied code chunk does not implement that workflow; it is a narrow helper module for time-window parsing/formatting and simple file-path lookup. While such utilities could support a reporting workflow, the actual code’s primary purpose is materially different and far more limited than the declared skill behavior.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises executable scripts that read environment variables, access the filesystem, write reports/state, and perform network requests, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens reviewability and policy enforcement because an agent may invoke capabilities broader than what the manifest makes obvious to users or security controls.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This file embeds a fixed Chinese locale in its generated document format, including Chinese font families and later Chinese section titles/content strings, with no opt-in or alternate locale path. That can violate language/locale policy when a skill forces a specific language experience rather than allowing user choice or clearly documenting a justified region-specific constraint.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The prompt text explicitly instructs the model in Chinese and requires Chinese-character length limits and Chinese punctuation, which forces a specific language/locale behavior. The file does not offer a user opt-in or language selection, and no region-specific justification is documented here.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The prompt explicitly instructs the model to generate the title and summary in Chinese and to translate ordinary English terms into Chinese. Because this is a code file, these natural-language strings are in scope for policy review, and there is no visible user choice or opt-in for language/locale behavior.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
This code sends report data to an external AI service despite the skill description emphasizing a self-contained workflow in the current workspace. The main danger is undisclosed data egress: titles, content, source, time, and links are transmitted off-box, which may violate user expectations, policy boundaries, or handling requirements for sensitive inputs.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Missing User Warnings

Low
Confidence
91% confidence
Finding
This markdown file documents outputs including multiple JSONL, Excel, and Word files, which means the skill modifies user workspace contents. Under SQP-2 for markdown files, descriptions should warn when behavior can affect user data or system state, but no warning or disclosure is provided near these instructions or output descriptions.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The markdown indicates that AI fields depend on ARK_API_KEY and model/API connectivity, implying data may be sent to external AI services during report generation. The skill description does not include a user-facing privacy or network-use warning, which is expected for markdown files when behavior may affect privacy or transmit data externally.

Context-Inappropriate Capability

Low
Confidence
83% confidence
Finding
The stated purpose is an AI news capture/report workflow with local cumulative outputs, but the script depends on externally supplied environment-based credentials and endpoint configuration. Reading ARK_API_KEY and related endpoint settings introduces a credential/configuration capability that is not reflected in the manifest's purpose description.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
def configure_output_encoding() -> None:
    for stream_name in ("stdout", "stderr"):
        stream = getattr(sys, stream_name, None)
        reconfigure = getattr(stream, "reconfigure", None)
        if callable(reconfigure):
            reconfigure(encoding="utf-8", errors="replace")
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
def configure_output_encoding() -> None:
    for stream_name in ("stdout", "stderr"):
        stream = getattr(sys, stream_name, None)
        reconfigure = getattr(stream, "reconfigure", None)
        if callable(reconfigure):
            reconfigure(encoding="utf-8", errors="replace")
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
def configure_output_encoding() -> None:
    for stream_name in ("stdout", "stderr"):
        stream = getattr(sys, stream_name, None)
        reconfigure = getattr(stream, "reconfigure", None)
        if callable(reconfigure):
            reconfigure(encoding="utf-8", errors="replace")
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Unpinned Dependencies

Low
Category
Supply Chain
Content
openpyxl
python-docx
Confidence
88% confidence
Finding
The dependency openpyxl is unpinned, which reduces build reproducibility and can result in unexpected installation of a vulnerable or breaking version in the future. Because this skill generates cumulative Excel outputs, the package is part of the main processing path and should be version-controlled for safety and stability.

Unpinned Dependencies

Low
Category
Supply Chain
Content
openpyxl
python-docx
Confidence
93% confidence
Finding
The dependency python-docx is unpinned, so installs may resolve to different versions over time, including vulnerable or incompatible releases. This is more concerning here because the skill processes document files, and python-docx has known historical security advisories involving XML parsing behavior.

Unverifiable Dependency: python-docx has 2 known advisory(ies) (CVE-2016-5851 (Improper Restriction of XML External Entity Reference in python-docx); CVE-2016-5851 (python-docx before 0.8.6 allows context-dependent attackers to conduct XML Exter)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding
The manifest does not pin python-docx, and that package has known advisories affecting some historical versions, including XML external entity handling. Since the installed version cannot be verified from this file, the environment could resolve to an affected release, which matters more in a workflow that creates or potentially handles Office documents.

Missing User Warnings

Low
Confidence
79% confidence
Finding
This code sets the AI_NEWS_WORKSPACE environment variable, which modifies process environment state and may influence downstream behavior, but there is no explicit user disclosure about this action. The existing step logs describe feed collection and report building, not the environment mutation itself.

Static analysis

No suspicious patterns detected.