Back to skill

Security audit

A-Share Review and Analyse

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stock-review purpose, but it handles credentials, publishing, and output paths unsafely enough that users should review it before installing.

Install only if you are comfortable running a local stock-report generator that can call Gemini and create WeChat drafts. Before using real WeChat credentials, fix or verify redaction of secrets in logs, validate dates as YYYYMMDD, remove the fixed demo-blog link from completion output, and run it in a workspace where writing data and content/posts is acceptable.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T01 · Skill Instruction Hijacking

Note
Location
SKILL.md:241
Finding

Fixed Promotional Link Injected into Agent Completion Responses

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_data.py:45
Finding

Unvalidated Date Allows Writes Outside the Configured Data Directory

Content
View full analysis
Dict[str, Any]: """ Get all market data for the specified date, with caching and retry logic Returns: A dictionary containing all the dataframes and summary statistics """ self.logger.info(f"Fetching market data for {date}") save_dir = self.config.data_dir / date save_dir.mkdir(parents=True, exist_ok=True) ``` The report generator repeats the unsafe path construction: ```python save_dir = self.config.data_dir / date file_path = save_dir / f"market_summary_{date}.md" ``` ```python def generate_all(self, market_data: Dict, market_summary: str, ai_analysis: Optional[str], date: str) -> Dict[str, Path]: save_dir = self.config.data_dir / date reports = {} reports['market_summary'] = save_dir / f"market_summary_{date}.md" if ai_analysis: ai_path = save_dir / f"ai_analysis_{date}.md" with open(ai_path, 'w', encoding='utf-8') as f: f.write(ai_analysis) reports['ai_analysis'] = ai_path return reports ``` ### Technical Analysis The `date` value is documented as `YYYYMMDD`, but the implementation does not validate that format before using the value as a filesystem path component. `pathlib.Path` preserves traversal components such as `..`. For example, if `self.config.data_dir` is `/workspace/data` and `date` is `..`, the expression below resolves operationally to the parent of the intended data directory: ```python Path("/workspace/data") / ".." ``` The fetcher then creates that directory and writes predictable CSV cache files beneath it. Report generation uses the same unvalidated value. The problem ...[truncated 1550 chars]
Remediation
View remediation
str: if not re.fullmatch(r"\d{8}", value): raise ValueError("Date must use YYYYMMDD format") datetime.strptime(value, "%Y%m%d") return value ``` 2. Resolve and enforce the output boundary: ```python base = self.config.data_dir.resolve() save_dir = (base / validate_date(date)).resolve() if save_dir.parent != base: raise ValueError("Output path escapes the configured data directory") ``` 3. Centralize date validation so the fetcher, report generator, and publishers use the same validated value. 4. Reject absolute paths, path separators, `.` components, and `..` components. 5. Add regression tests using `..`, `../target`, absolute paths, malformed dates, and invalid calendar dates. 6. Run the Skill under an account with write access only to its intended data and content directories. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:71
Finding

Environment File Loading Order Can Silently Replace Intended Credentials

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/post_to_wechat.py:208
Finding

WeChat Secrets and Access Tokens Can Be Exposed Through Exception Logging

Content
View full analysis
Optional[str]: """Get access token from WeChat API""" app_id = self.config.wechat_app_id app_secret = self.config.wechat_app_secret if not app_id or not app_secret: self.logger.error("WeChat app_id or app_secret not configured") return None url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={app_id}&secret={app_secret}" try: self.logger.info("Requesting WeChat access token...") response = requests.get(url, timeout=10) result = response.json() if 'access_token' in result: token = result['access_token'] self.logger.info("✅ Access token obtained successfully") return token else: self.logger.error(f"❌ Failed to get access token: {result}") return None except Exception as e: self.logger.error(f"Access token request failed: {e}") return None ``` The access token is handled in the same way during image upload: ```python def _upload_image_as_thumb(self, access_token: str, image_path: str) -> Optional[str]: if not os.path.exists(image_path): self.logger.error(f"Cover image not found: {image_path}") return None url = f"https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={access_token}&type=image" try: self.logger.info(f"Uploading cover image: {image_path}") with open(image_path, 'rb') as f: files = {'media': f} response = requests.post(url, files=files, timeout=30) result = resp ...[truncated 2590 chars]
Remediation
View remediation
str: parts = urlsplit(url) query = [ (key, "[REDACTED]" if key.lower() in SENSITIVE_KEYS else value) for key, value in parse_qsl(parts.query, keep_blank_values=True) ] return urlunsplit(( parts.scheme, parts.netloc, parts.path, urlencode(query), parts.fragment, )) ``` 3. Log only the exception class and a sanitized operational message: ```python self.logger.error( "WeChat access-token request failed (%s)", type(e).__name__, ) ``` 4. Ensure file, proxy, HTTP-access, and centralized logs apply equivalent redaction. 5. Restrict log-file permissions and retention. 6. Rotate the AppSecret immediately if logs may already contain it, and invalidate exposed access tokens where supported. 7. Preserve WeChat IP allowlisting and apply the narrowest API permissions available. 8. Add tests that generate request exceptions and assert that credential values never appear in captured logs. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (66)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/fetch_data.py` | Fetch A-share market data (indices, stocks, sectors, etc.) |

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 · scripts/check_env.py (reported line 42)May include surrounding context.

python
def check_env_vars():
    """检查环境变量"""
    env_file = Path(__file__).parent.parent / '.env'
    if env_file.exists():
        print(f"✅ 找到.env文件: {env_file}")
    else:

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 · scripts/config.py (reported line 81)May include surrounding context.

python
def check_env_vars():
    """检查环境变量"""
    env_file = Path(__file__).parent.parent / '.env'
    if env_file.exists():
        print(f"✅ 找到.env文件: {env_file}")
    else:

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 · scripts/config.py (reported line 82)May include surrounding context.

python
def check_env_vars():
    """检查环境变量"""
    env_file = Path(__file__).parent.parent / '.env'
    if env_file.exists():
        print(f"✅ 找到.env文件: {env_file}")
    else:

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 · scripts/config.py (reported line 83)May include surrounding context.

python
def check_env_vars():
    """检查环境变量"""
    env_file = Path(__file__).parent.parent / '.env'
    if env_file.exists():
        print(f"✅ 找到.env文件: {env_file}")
    else:

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 · scripts/config.py (reported line 85)May include surrounding context.

python
def check_env_vars():
    """检查环境变量"""
    env_file = Path(__file__).parent.parent / '.env'
    if env_file.exists():
        print(f"✅ 找到.env文件: {env_file}")
    else:

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 · SKILL.md (reported line 40)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · SKILL.md (reported line 44)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · SKILL.md (reported line 90)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · SKILL.md (reported line 134)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · SKILL.md (reported line 135)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · SKILL.md (reported line 338)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · SKILL.zh.md (reported line 338)May include surrounding context.

md
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/config.py (reported line 15)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/config.py (reported line 71)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/config.py (reported line 95)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/config.py (reported line 97)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/main.py (reported line 33)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/main.py (reported line 43)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/main.py (reported line 48)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

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 · scripts/main.py (reported line 50)May include surrounding context.

python
def __init__(self, config: Optional[Dict[str, Any]] = None):
        config = config or {}
        
        # step 1. load .env files
        self._load_env_files()
        
        # step 2. load environment variables with fallback to config dict

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/post_to_wechat.py (reported line 41)May include surrounding context.

python
return None
        
        try:
            # 1. Get access token
            token = self._get_access_token()
            if not token:
                self.logger.error("Failed to get access token")

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/post_to_wechat.py (reported line 44)May include surrounding context.

python
return None
        
        try:
            # 1. Get access token
            token = self._get_access_token()
            if not token:
                self.logger.error("Failed to get access token")

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/post_to_wechat.py (reported line 209)May include surrounding context.

python
return None
        
        try:
            # 1. Get access token
            token = self._get_access_token()
            if not token:
                self.logger.error("Failed to get access token")

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/post_to_wechat.py (reported line 229)May include surrounding context.

python
return None
        
        try:
            # 1. Get access token
            token = self._get_access_token()
            if not token:
                self.logger.error("Failed to get access token")