Back to skill

Security audit

Zonebourse

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned for retrieving ZoneBourse articles, but it handles subscriber session cookies in a way that can expose account access.

Review this skill before installing. Only use it with cookies for an account you control, treat cookies.txt as a password-equivalent secret, restrict its file permissions, and do not run read_article.py on URLs unless they are verified ZoneBourse HTTPS article links. The implementation should be hardened with hostname allowlisting before relying on subscriber cookies.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/read_article.py:58
Finding

Authentication Cookies Sent to Arbitrary User-Controlled Destinations

Content
View full analysis
dict: """Récupère titre + contenu complet d'un article ZoneBourse.""" cookie_header = load_cookies(COOKIES_FILE) cmd = CURL_ARGS + ["-H", f"Cookie: {cookie_header}", url] result = subprocess.run(cmd, capture_output=True, text=True, timeout=20) ``` The destination is taken directly from a command-line argument: ```python if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python3 read_article.py ") sys.exit(1) result = fetch_article(sys.argv[1]) print(json.dumps(result, indent=2, ensure_ascii=False)) ``` ### Technical Analysis `fetch_article()` loads every entry from the local `cookies.txt` file and constructs a `Cookie` request header. According to `SKILL.md`, this file may contain sensitive subscriber credentials such as `zb_auth`, `zb_abonne`, `zb_membre`, and `PHPSESSID`. The destination URL is accepted from `sys.argv[1]` without validating its scheme, hostname, port, or path. The script therefore sends the subscriber cookies to any destination supplied by the caller, rather than restricting their transmission to the intended ZoneBourse HTTPS origin. The command also places the untrusted argument directly into the curl argument list without an explicit `--` option terminator. Although use of an argument list prevents shell metacharacter injection, a value beginning with `-` may still be interpreted by curl as an option. This increases the attack surface and should be addressed alongside strict URL validation. Redirect behavior should also be constrained during remediation. Although the current curl arguments do not explicitly enable redirect following, future changes must not permit credentials to be f ...[truncated 1463 chars]
Remediation
View remediation
str: parsed = urlsplit(url) if parsed.scheme != "https": raise ValueError("Only HTTPS URLs are allowed") if parsed.hostname not in ALLOWED_HOSTS: raise ValueError("Unapproved destination host") if parsed.port not in (None, 443): raise ValueError("Unapproved destination port") if parsed.username is not None or parsed.password is not None: raise ValueError("URL credentials are not allowed") if not parsed.path.startswith("/actualite-bourse/"): raise ValueError("Unexpected article path") return url def fetch_article(url: str) -> dict: validated_url = validate_article_url(url) cookie_header = load_cookies(COOKIES_FILE) cmd = CURL_ARGS + [ "-H", f"Cookie: {cookie_header}", "--", validated_url, ...[truncated 129 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (15)

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Confidence
91% confidence
Finding

The skill instructs the user to install a browser cookie export plugin, log into the target site, export cookies in Netscape format, and copy selected authenticated cookies into a local file. Those are classic credential-handling and session extraction steps; while not overtly malicious, they mirror information-stealer behavior because they facilitate exfiltration and reuse of authentication material.

Content

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

md
ormat simplifié, une ligne `key=value` par cookie).

### Durée des cookies

**Le JWT (`zb_auth`) expire après 7 jours.** Quand il expire, les articles reviennent en paywall.

**Quand le cookie expire, demander à Fred de renvoyer ses cookies** (format Netscape, via le plugin navigateur "Export Cookies" pour ZoneBourse).

### Mettre à jour les cookies

1. Installer le plugin navigateur "Export Cookies" pour Chrome/Firefox
2. Aller sur zonebourse.com et se connecter
3. Exporter les cookies au format Netscape
3. Copier le contenu dans `~/.openclaw/workspace/skills/zonebourse/scripts/cookies.txt`
   - Conserver uniquement les cookies essentiels : `zb_auth`, `zb_abonne`, `zb_membre`, `PHPSESSID`, `pv_r0`, `pv_r0_date`, `pv_r0_rand`, `hmv`
   - Supprimer `g_state` (trop volumineux, pose des problèmes avec le format Netscape)

## Rate Limiting

- 2-5 sec entre requêtes
- Pour les tests : `sleep 2` entre chaque appel

## Notes importantes

- **User-Agent Chrome complet requis** pour les

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

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

md
| WLN | WORLDLINE-16783982 |
| AI | AIR-LIQUIDE-4605 |
| NVDA | NVIDIA-CORPORATION-57355629 |
| SU | SCHNEIDER-ELECTRIC-SE-4699 |
| MSFT | MICROSOFT-CORPORATION-4835 |
| RNO | RENAULT-4688 |
| STLAM | STELLANTIS-N-V-117814143 |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly instructs the user to export authenticated ZoneBourse session cookies, store them locally, and share refreshed cookies when the JWT expires. Session cookies such as zb_auth and PHPSESSID can grant direct account access, so handling them this way creates a credential exposure and session hijacking risk even if the stated goal is only to access subscriber content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The Accept-Language header forces a French-first locale preference (fr-FR, fr) for all requests. This is a natural-language/locale policy concern because the script imposes a language setting without offering the user a choice or clearly documenting a justified region-specific requirement.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/parse_actus.py (reported line 49)May include surrounding context.

python
"""Récupère les liens d'actualité depuis les 3 sections de la page cours."""
    url = f"https://www.zonebourse.com/cours/action/{slug}/"
    
    result = subprocess.run(CURL_ARGS + [url], capture_output=True, text=True, timeout=20)
    html = result.stdout

    results = {k: [] for k in SECTION_IDS}

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script reads local cookies from a file and automatically attaches them to outbound requests, allowing authenticated session material to be used without clear user consent or scope restriction. This can expose private account context to any supplied URL if the caller passes an unexpected host, and it normalizes credential use in a utility whose stated purpose is only article retrieval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code sends the locally loaded Cookie header on every request without warning, disclosure, or host validation. If an attacker can influence the URL argument, they can cause the script to transmit session cookies to an arbitrary remote server, resulting in credential leakage or account compromise.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/read_article.py (reported line 61)May include surrounding context.

python
cookie_header = load_cookies(COOKIES_FILE)

    cmd = CURL_ARGS + ["-H", f"Cookie: {cookie_header}", url]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=20)
    html = result.stdout

    if result.returncode != 0 or len(html) < 200:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring is written only in French, indicating a language-specific interaction pattern without offering user opt-in or documenting a justified locale restriction. Under the policy, forcing a specific language without choice can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/search_slug.py (reported line 7)May include surrounding context.

python
import subprocess, json, re, sys

def search_slug(query: str) -> list[str]:
    result = subprocess.run([
        "curl", "-s", "-X", "POST",
        "https://www.zonebourse.com/async/search/quick",
        "-H", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8",

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill description is written entirely in French, which can constitute a language-policy issue when the file implicitly assumes a single language for users without documenting an opt-in or locale-specific justification. There is no indication that the skill is intended only for French-speaking users or a French-market context.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring states that article links end with a 16-character hexadecimal hash, but the implemented regex in is_article_link accepts exactly 16 hex characters while the module-level documentation earlier describes 10-12 characters. This is an active documentation inconsistency about what qualifies as an article link, which can mislead maintainers about the function's real behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code performs an outbound HTTP request by invoking curl against a third-party website, but there is no user-facing disclosure at the call site beyond an internal docstring. For code files, outbound network activity that transmits user-provided input should include some visible warning, confirmation, or explicit disclosure unless clearly surfaced to the user.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The hard-coded Accept-Language header prioritizes fr-FR/fr, which imposes a specific locale on all requests. This is a natural-language/locale policy concern because the script does not offer an opt-in, configuration option, or explanation that the skill is intentionally restricted to French content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code sends the user's query to an external website using curl, which is a network operation that transmits user-supplied data off-system. While the script's purpose implies searching ZoneBourse, there is no confirmation prompt, print/log notice, or explanatory comment/docstring stating that the query will be sent to a third-party service.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.