Back to skill

Security audit

bazi-pillars-from-datetime

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to perform its stated Bazi chart and analysis tasks, but its location lookup can send location data externally and write a cache to an arbitrary caller-supplied path.

Review before installing. Prefer supplying longitude and latitude directly or forcing local-only lookup. Avoid passing sensitive API keys unless needed, and run the skill with low filesystem privileges or remove caller-controlled cache_path and lookup_path support so it cannot overwrite unrelated writable files.

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

Error
Location
main.py:272
Finding

User-Controlled Cache Path Allows Arbitrary File Overwrite

Content
View full analysis
None: if not path: return try: with open(path, "w", encoding="utf-8") as f: json.dump(cache, f, ensure_ascii=False, indent=2) except Exception: return ``` ```python cache_path = location.get("cache_path") or DEFAULT_CACHE_PATH provider = location.get("lookup_provider") or DEFAULT_LOOKUP_PROVIDER key = location.get("lookup_key") or os.environ.get("BAZI_GEOCODE_KEY", "") timeout = location.get("lookup_timeout", DEFAULT_LOOKUP_TIMEOUT) try: timeout = float(timeout) except Exception: timeout = DEFAULT_LOOKUP_TIMEOUT norm = normalize_city_name(name) global _CITY_INDEX if _CITY_INDEX is None or lookup_path != DEFAULT_CITY_MAP_PATH: _CITY_INDEX = build_city_index(load_city_map(lookup_path)) if lookup_mode in ("local", "auto"): if norm in _CITY_INDEX: lon, lat, canonical = _CITY_INDEX[norm] return lon, lat, canonical cache = load_cache(cache_path) if norm in cache: try: lon, lat = cache[norm]["longitude"], cache[norm]["latitude"] return float(lon), float(lat), cache[norm].get("name", norm) except Exception: pass if lookup_mode in ("online", "auto"): try: coords = geocode_online(name, provider, key, timeout) except Exception: coords = None if coords: lon, lat = coords cache[norm] = {"longitude": lon, "latitude": lat, "name": name} save_cache(cache_path, cache) ``` ### Technical Analysis The `location.cache_path` field comes directly from the JSON payload and is passed to `save_cache()` without path validation, directory confinement, ownership checks, or symbolic-link protection. The sink opens the selected path in write mode, which t ...[truncated 2327 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:205
Finding

Location Data and Geocoding API Keys Are Transmitted in Request URLs

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Tainted flow: 'timeout' from os.environ.get (line 282, credential/environment) → urllib.request.urlopen (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 · main.py (reported line 214)May include surrounding context.

python
url = f"https://nominatim.openstreetmap.org/search?format=json&limit=1&q={query}"
    headers = {"User-Agent": "opencode-bazi/1.0"}
    req = urllib.request.Request(url, headers=headers)
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        data = json.loads(resp.read().decode("utf-8"))
    if not data:
        return None

Tainted flow: 'timeout' from os.environ.get (line 282, credential/environment) → urllib.request.urlopen (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 · main.py (reported line 227)May include surrounding context.

python
return None
    query = urllib.parse.quote(name)
    url = f"https://restapi.amap.com/v3/geocode/geo?address={query}&key={key}"
    with urllib.request.urlopen(url, timeout=timeout) as resp:
        data = json.loads(resp.read().decode("utf-8"))
    geocodes = data.get("geocodes") or []
    if not geocodes:

Tainted flow: 'timeout' from os.environ.get (line 282, credential/environment) → urllib.request.urlopen (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 · main.py (reported line 244)May include surrounding context.

python
return None
    query = urllib.parse.quote(name)
    url = f"https://restapi.amap.com/v3/geocode/geo?address={query}&key={key}"
    with urllib.request.urlopen(url, timeout=timeout) as resp:
        data = json.loads(resp.read().decode("utf-8"))
    geocodes = data.get("geocodes") or []
    if not geocodes:

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented purpose understates important behaviors: the skill can call external geocoding providers, read local mapping files, and persist cache data, while also claiming an analysis capability that is not actually implemented in code. This mismatch is dangerous because users and orchestrators may authorize the skill for harmless chart generation while unknowingly permitting outbound data transfer and filesystem interaction, which can expose sensitive birthplace data or modify local state.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises operational behavior that includes environment-variable use, local file access, cache writes, and possible network geocoding, but it does not declare any explicit tool scope or permissions boundary. That creates an authorization and review gap: an agent or reviewer may treat the skill as narrower and safer than it really is, increasing the chance of unintended data access, persistence, or outbound requests during execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The knowledge file is written entirely in Chinese and frames output style around Chinese-language analysis, while the skill metadata says it may generate analysis in the user's language. This can cause the agent to ignore user language preference, reducing usability and potentially causing misunderstanding if users cannot read the response.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code reads provider and geocoding key settings from environment variables, enabling external network integrations that are not obvious from the declared skill purpose. This hidden capability increases the chance of unexpected data transfer and use of privileged runtime secrets in ways users may not anticipate.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description suggests local chart derivation, but the code can send user-provided location names to third-party geocoding services. That expands the trust boundary and can disclose sensitive birthplace or residence data without being clearly required by or disclosed in the stated skill purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

When local lookup misses, the code may transmit user-provided location names to external geocoding providers without any in-file disclosure, consent flow, or audit signal. Because Bazi inputs can involve sensitive personal data such as birthplace, this undisclosed sharing is a meaningful privacy issue in the skill context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill persists a geocoding cache to disk, storing user-supplied location lookups beyond the current execution. In a shared or multi-tenant environment, this creates an unnecessary privacy and retention risk not clearly justified by the core calculation function.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The cache file is written silently, creating persistent storage of location-derived data without visible disclosure. Even if the contents are limited to coordinates and names, silent retention can violate privacy expectations and leak data to other local users or processes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The prompt states that if the user's language cannot be identified, the assistant should default to Simplified Chinese. This imposes a locale/language choice without user opt-in, which matches the language policy violation category.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This line reinforces a fixed fallback language requirement rather than offering a user choice. Because the policy applies across all outputs and lacks explicit opt-in, it constitutes a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.