Back to skill

Security audit

Xiaoqian

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it exposes reusable government-portal credentials and stores sensitive meeting data in ways users should review before installation.

Install only if you are authorized to access this Jiangsu MSA portal account and accept local storage of exported meeting data. The embedded password should be treated as compromised and rotated; credentials should come from a protected secret source, the portal should be accessed over HTTPS, dependencies and ChromeDriver should be pinned or preinstalled, and JSON backups should be removed or made explicit opt-in with restricted permissions.

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

T09 · Insecure Skill Coding Practices

Error
Location
query_meetings.py:55
Finding

Hardcoded Credentials Transmitted Through an Insecure HTTP Login Page

Content
View full analysis

Vulnerability Details

File Location: query_meetings.py:55-57, query_meetings.py:94-109; credentials are also disclosed in SKILL.md:33-35
Vulnerability Type: Hardcoded secrets and plaintext authentication
Risk Level: Critical

Vulnerable Code

python
self.base_url = "http://gchportal.js-msa.gov.cn/cas/login"
self.username = os.getenv("MSA_USERNAME", "lp@njmsa")
self.password = os.getenv("MSA_PASSWORD", "@lp280033")
python
logger.info(f"Accessing login page: {self.base_url}")
self.driver.get(self.base_url)
time.sleep(2)

username_input = self.wait.until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='username'], input[type='text']"))
)
password_input = self.driver.find_element(
    By.CSS_SELECTOR,
    "input[name='password'], input[type='password']"
)

username_input.clear()
username_input.send_keys(self.username)

password_input.clear()
password_input.send_keys(self.password)

The original logging message in the source is written in Chinese; it is translated above without changing the executable behavior.

SKILL.md also publishes the same account and password in its system configuration section.

Technical Analysis

The source code contains reusable default credentials. Environment variables only override these values; they do not prevent the embedded defaults from being used. Anyone who can obtain the project package can recover the username and password without executing the program.

The browser initially loads the authentication page through unencrypted HTTP. Even if the server subsequently redirects to HTTPS, the first HTTP response can be intercepted and modified by a network-positioned attacker. Such an attacker could prevent the redirect, replace the login form, change its submission endpoint, or inject browser-side code that captures the credentials.

This combines secret disclosure with a transport-security failure. The account ...[truncated 1330 chars]

Remediation
View remediation

Remediation Suggestions

  1. Immediately disable or rotate the exposed account password and review its authentication history.
  2. Remove the username and password from source code, documentation, release artifacts, and version history.
  3. Require credentials to be supplied through a managed secret store or protected environment variables. Abort execution if either value is absent.
  4. Replace the HTTP URL with the authoritative HTTPS endpoint.
  5. Configure the browser workflow to reject certificate errors, insecure redirects, and any downgrade to HTTP.
  6. Use a dedicated read-only service account restricted to the minimum meeting-query permissions.
  7. Add automated secret scanning to the development and release pipeline.
  8. Review whether the same password was reused on other systems and rotate it wherever applicable.

T08 · Insecure Dependencies

Error
Location
query_meetings.py:76
Finding

Runtime Download and Execution of an Unpinned WebDriver

Content
View full analysis

Vulnerability Details

File Location: query_meetings.py:76; dependency constraints in requirements.txt:1-4
Vulnerability Type: Unsafe runtime executable retrieval and unpinned dependencies
Risk Level: High

Vulnerable Code

python
service = Service(ChromeDriverManager().install())
self.driver = webdriver.Chrome(service=service, options=chrome_options)
text
selenium>=4.15.0
pandas>=2.0.0
openpyxl>=3.1.0
webdriver-manager>=4.0.0

Technical Analysis

ChromeDriverManager().install() retrieves a ChromeDriver executable at runtime. That executable is then launched by Selenium with the privileges of the user running the Skill. The audited package therefore does not fully determine the code that will execute during a future invocation.

In addition, all Python dependencies use open-ended minimum-version constraints and no integrity hashes. A later installation can consequently resolve to dependency versions that were not reviewed. This creates avoidable exposure to compromised package releases, compromised distribution infrastructure, malicious mirrors, and future dependency behavior changes.

The audit found no evidence that the currently named packages are intentionally malicious. The vulnerability is the absence of deterministic versions and artifact-integrity controls around code and executables obtained from the supply chain.

Attack Path

  1. A user installs the requirements at a later date, allowing the package manager to select versions newer than those reviewed.
  2. A dependency source, package release, driver distribution channel, mirror, DNS route, or local package index is compromised or misconfigured.
  3. The Skill invokes ChromeDriverManager().install().
  4. A modified driver executable is downloaded or selected from an unsafe cache.
  5. Selenium starts that executable under the current user's account.
  6. The malicious executable can access files, envi ...[truncated 652 chars]
Remediation
View remediation

Remediation Suggestions

  1. Preinstall a trusted ChromeDriver through the deployment image or operating-system package process instead of downloading it during execution.
  2. Pin the exact expected driver version and verify its cryptographic checksum or vendor signature before use.
  3. Pin every Python dependency to an exact reviewed version.
  4. Generate and enforce a lock file containing cryptographic hashes, such as with pip-tools and pip install --require-hashes.
  5. Restrict package installation to an authenticated organizational repository containing approved artifacts.
  6. Perform dependency vulnerability and provenance scanning during builds.
  7. Build an immutable runtime image and run the Skill as a non-administrative user in a restricted container or sandbox.
  8. Prevent the runtime from writing executable files or making unnecessary outbound connections.

T09 · Insecure Skill Coding Practices

Error
Location
query_meetings.py:517
Finding

Spreadsheet Formula Injection Through Untrusted Meeting Fields

Content
View full analysis

Vulnerability Details

File Location: query_meetings.py:517-523, with the unsafe export at query_meetings.py:608
Vulnerability Type: Spreadsheet formula injection
Risk Level: High

Vulnerable Code

python
meeting_data = {
    "日期": cells[0].text.strip() if len(cells) > 0 else "",
    "开始时间": cells[1].text.strip() if len(cells) > 1 else "",
    "会议标题": cells[2].text.strip() if len(cells) > 2 else "",
    "会议地点": cells[3].text.strip() if len(cells) > 3 else "",
    "出席人员": cells[4].text.strip() if len(cells) > 4 else "",
    "主办部门": cells[5].text.strip() if len(cells) > 5 else "",
    "行号": i
}
meetings.append(meeting_data)
python
df = pd.DataFrame(meetings)
df.to_excel(output_path, index=False, engine='openpyxl')

The dictionary keys above are retained exactly as they appear in the source because they are part of the executable code.

Technical Analysis

Values extracted from the portal are transferred directly into an XLSX workbook without validation or formula neutralization. In particular, openpyxl treats strings beginning with = as formulas when they are assigned to cells.

Consequently, any party capable of controlling a meeting title, location, attendee field, department, or other exported value may be able to place a spreadsheet formula in the generated workbook. Formula execution occurs when a recipient opens or recalculates the workbook.

The effect depends on the spreadsheet client and its security configuration. Possible payloads include deceptive hyperlinks, external-resource requests that disclose contextual data, and abuse of client-specific formula or external-link functionality. This finding does not assume that every spreadsheet client permits operating-system command execution.

Attack Path

  1. An attacker obtains permission to create or modify a meeting record in the queried portal, or compromises an account with that permiss ...[truncated 1023 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat every portal-derived value as untrusted before spreadsheet export.
  2. Convert values beginning with =, and any additional prefixes considered dangerous by the supported spreadsheet clients, into literal text.
  3. A common neutralization approach is to prefix unsafe values with an apostrophe before assigning them to spreadsheet cells.
  4. Prefer explicit cell creation with a text data type when reliable preservation of the displayed value is required.
  5. Apply sanitization to all columns rather than only titles or attendee fields.
  6. Add automated tests using formula payloads in every exported field and verify that the resulting XLSX cells are stored as text.
  7. Warn recipients that exported records originate from portal-controlled content and should be opened with external links and active content disabled.

T09 · Insecure Skill Coding Practices

Warning
Location
query_meetings.py:612
Finding

Undisclosed Plaintext JSON Copy of Sensitive Meeting Data

Content
View full analysis

Vulnerability Details

File Location: query_meetings.py:612-615; declared Excel output in SKILL.md:22,42-49
Vulnerability Type: Insecure storage and undeclared duplication of sensitive data
Risk Level: Medium

Vulnerable Code

python
# Save raw data as JSON backup
json_path = output_path.replace('.xlsx', '.json')
with open(json_path, 'w', encoding='utf-8') as f:
    json.dump(meetings, f, ensure_ascii=False, indent=2)
logger.info(f"Raw data saved to: {json_path}")

The comments and log message in the original source are written in Chinese; they are translated above without changing the executable statements.

Technical Analysis

The Skill declares Excel as its output format, but every successful export also creates a separate plaintext JSON file. That file contains the complete meeting records, including meeting locations and attendee information.

The JSON copy is created automatically without explicit user consent, encryption, a retention policy, restrictive permission handling, or an opt-out option. Python's ordinary open call uses permissions derived from the current process umask; the code does not ensure that only the invoking user can read the file.

The filename is also derived with a general string replacement rather than a path-aware suffix operation. Although the default filename ends in .xlsx, unusual caller-supplied paths could result in an unexpected JSON location or even no suffix change.

Attack Path

  1. A legitimate user executes a meeting query.
  2. The Skill writes the expected XLSX report.
  3. Without an additional request, the Skill writes the same records to a nearby JSON file.
  4. The JSON file remains on disk after execution.
  5. Another local user, process, backup system, synchronization client, indexing service, or recipient of the containing directory gains access to the undeclared copy.
  6. Sensitive meeting and attendee information is disclosed outside ...[truncated 587 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the automatic JSON backup unless it is an explicit functional requirement.
  2. If JSON export is required, make it an opt-in command-line option and document it in the Skill output contract.
  3. Write sensitive output only to an approved directory with restrictive access controls.
  4. Create files with owner-only permissions and verify permissions after creation.
  5. Encrypt sensitive exports at rest when required by organizational policy.
  6. Use pathlib.Path.with_suffix(".json") to derive the backup path safely.
  7. Define and enforce retention and secure-deletion rules for all generated artifacts.
  8. Avoid logging full sensitive paths if logs are accessible to broader audiences.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code embeds default credentials, including a hardcoded fallback password, which can expose real account access to anyone with source access or logs/environment visibility. In a government-system automation script, this is especially dangerous because it can enable unauthorized access if the defaults are valid or reused elsewhere.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger phrases are broad enough to overlap with normal meeting-related conversation, which can cause the automation to activate when the user did not clearly intend to invoke it. In this skill, unintended activation is more dangerous because it can initiate login to an external government platform and query/export potentially sensitive meeting data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill documentation exposes a live-looking username and password directly in the file, which is a credential disclosure issue. Even though the notes mention environment variables, the actual hardcoded secrets can be copied, reused, or tested against the target platform, enabling unauthorized access and downstream data exposure.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The usage examples describe natural-language requests without clearly defining activation boundaries, making it easy for ordinary discussion about meetings to be misinterpreted as an execution request. Because this skill performs authenticated web automation and data export, ambiguous invocation increases the risk of unauthorized or accidental access to sensitive scheduling information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script writes potentially sensitive meeting information, including titles, locations, attendees, and departments, to local Excel and JSON files without explicit user consent, retention controls, or protection. In this context, meeting data from a government portal may contain internal or sensitive operational information, so silent persistence to disk increases the risk of unintended disclosure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The skill is entirely documented and presented in Chinese, with no indication that the user can choose another language or locale. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code unconditionally sets the Chrome browser language to Chinese with --lang=zh-CN. This is a locale policy issue because it imposes a specific language setting without opt-in, fallback, or documentation that the skill is intentionally limited to a Chinese-only environment.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The top-level docstring describes the script's function as logging in, querying meeting information, and exporting it to Excel. However, the export routine additionally saves the full meeting dataset as a separate JSON file, which is an extra persistence behavior not reflected in the documented functionality.

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, so installs are not reproducible and may pull in different Selenium releases over time. This increases supply-chain and stability risk because vulnerable or breaking versions could be resolved without review, especially given Selenium has known advisories in some versions.

Content

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

text
selenium>=4.15.0
pandas>=2.0.0
openpyxl>=3.1.0
webdriver-manager>=4.0.0

Unverifiable Dependency: selenium has 2 known advisory(ies) (CVE-2022-28108 (Selenium Server (Grid) before 4 allows CSRF because it permits non-JSON content ); CVE-2023-5590 (NULL Pointer Dereference in GitHub repository seleniumhq/selenium prior to 4.14.)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding

Selenium has known advisories in some versions, but because the manifest does not pin an exact version, it is impossible to verify whether deployments will avoid affected releases. In this file, the minimum version 4.15.0 likely avoids the cited older issues, but the lack of pinning still prevents reliable verification and controlled installs.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using pandas>=2.0.0 leaves the actual installed version undefined, which undermines reproducibility and makes it harder to verify security posture. Even if the minimum version is modern, future resolution could introduce unreviewed versions or transitive dependency changes.

Content

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

text
selenium>=4.15.0
pandas>=2.0.0
openpyxl>=3.1.0
webdriver-manager>=4.0.0

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The openpyxl dependency is not pinned to a single version, so builds may resolve to different releases over time. This creates a supply-chain hygiene weakness and makes it difficult to prove that known-vulnerable versions are excluded.

Content

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

text
selenium>=4.15.0
pandas>=2.0.0
openpyxl>=3.1.0
webdriver-manager>=4.0.0

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

webdriver-manager is also specified as a minimum version only, allowing non-deterministic dependency resolution. Because this package influences browser driver acquisition, uncontrolled upgrades can affect both security and execution behavior.

Content

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

text
selenium>=4.15.0
pandas>=2.0.0
openpyxl>=3.1.0
webdriver-manager>=4.0.0

Static analysis

No suspicious patterns detected.