Back to skill

Security audit

homework-grade

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it handles email credentials, untrusted ZIP attachments, student code, and grading records with unsafe scoping and validation.

Review before installing. Use only a dedicated QQ mailbox and app-specific authorization code, process mail only from trusted senders, and run this skill in an isolated workspace with no sensitive files or host credentials. Do not rely on the generated grades without review, because student submissions can influence the AI prompt. The ZIP download and extraction code should be fixed before production use.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
modules/email_fetcher.py:18
Finding
Arbitrary File Write Through an Untrusted Email Attachment Filename<![CDATA[ ## Vulnerability Details **File Location**: `modules/email_fetcher.py:18-28` **Vulnerability Type**: Path traversal and arbitrary file write **Risk Level**: High ### Vulnerable Code ```python for part in msg.walk(): if part.get_content_disposition() == 'attachment': filename = part.get_filename() if filename and filename.endswith(".zip"): path = f"data/downloads/{filename}" with open(path, 'wb') as f: f.write(part.get_payload(decode=True)) file_paths.append(path) ``` ### Technical Analysis The MIME attachment filename is controlled by the email sender and is concatenated directly into a local filesystem path. The implementation does not reduce the value to a basename, reject absolute paths, normalize traversal components, or verify that the resolved destination remains inside `data/downloads`. Consequently, a filename containing path separators or traversal components can cause the attachment to be written outside the intended download directory. The `.zip` suffix check does not prevent path traversal. ### Attack Path 1. An attacker sends an unread email to the monitored mailbox. 2. The email contains an attachment whose MIME filename includes traversal components and ends in `.zip`. 3. `fetch_attachments` concatenates the filename with `data/downloads/`. 4. The process opens the resulting path without a containment check. 5. If the destination is writable, the attachment overwrites or creates a file outside the download directory. ### Impact Assessment The attacker can write files with the privileges of the Skill process. The practical scope includes application data, configuration, or source files writable by that account. Overwriting a Python module or another subsequently loaded file could potentially lead to code execution during a later process invocation. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Decode the MIME filename safely and reduce it to a basename using `pathlib.Path(filename).name`. - Reject absolute paths, parent-directory components, path separators, NUL characters, and empty filenames. - Resolve both the download root and destination, then verify that the destination is contained within the download root. - Generate a server-controlled random filename rather than trusting the sender's filename. - Create the download directory explicitly with restrictive permissions. - Prevent unintended replacement by opening new files in exclusive-creation mode where appropriate. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
modules/extractor.py:4
Finding
Unsafe Extraction of Untrusted ZIP Archives<![CDATA[ ## Vulnerability Details **File Location**: `modules/extractor.py:4-10` **Vulnerability Type**: Unsafe archive extraction and arbitrary file overwrite **Risk Level**: Critical ### Vulnerable Code ```python def unzip_file(zip_path): extract_path = zip_path.replace("downloads", "extracted").replace(".zip", "") os.makedirs(extract_path, exist_ok=True) with zipfile.ZipFile(zip_path, 'r') as zip_ref: zip_ref.extractall(extract_path) ``` ### Technical Analysis ZIP files received from email are passed directly to `extractall` without an explicit validation pass over archive members. The code does not enforce a canonical extraction-root containment policy or reject absolute paths, parent-directory components, links, special files, excessive member counts, or excessive expanded sizes. Relying solely on the archive API without application-level member validation creates unsafe extraction behavior and leaves the workflow exposed to malicious archive structures and resource-exhaustion archives. ### Attack Path 1. An attacker sends a crafted ZIP archive to the monitored mailbox. 2. The attachment passes the filename extension check and is saved locally. 3. `unzip_file` creates an extraction directory derived from the attachment path. 4. The archive is extracted without validating every member and its resolved destination. 5. A malicious member may attempt to escape the expected extraction root or overwrite a sensitive writable file. 6. If application source is replaced, attacker-controlled code may execute when the affected module is later imported or the application restarts. ### Impact Assessment Successful exploitation can modify files accessible to the Skill process, corrupt grading data, alter application behavior, or create a path to code execution. Independently, a ZIP bomb can consume disk, memory, or processing resources and cause denial of service. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Inspect every archive member before extraction. - Reject absolute paths, parent-directory traversal, drive-qualified paths, links, devices, and other special entries. - Resolve each proposed destination and verify that it remains beneath a dedicated extraction root. - Extract files individually only after validation instead of calling unrestricted bulk extraction. - Apply limits for compressed size, expanded size, compression ratio, file count, path depth, and extraction time. - Use a newly created, permission-restricted directory for each archive. - Run extraction under a low-privilege account and prevent writes to application source and configuration directories. ]]>

T01 · Skill Instruction Hijacking

Error
Location
modules/ai_grader.py:16
Finding
Student-Controlled Prompt Injection Can Manipulate AI Grades<![CDATA[ ## Vulnerability Details **File Location**: `modules/ai_grader.py:16-46` **Vulnerability Type**: Prompt injection through untrusted student source code **Risk Level**: High ### Vulnerable Code ```python def ai_grade(student_dir, template_dir): student_code = read_code(student_dir) template_code = read_code(template_dir) prompt = f""" You are a strict but fair programming teacher. Grade the student's assignment according to the reference answer. [Grading criteria] 1. Functional correctness: 50 points 2. Code structure: 20 points 3. Coding conventions: 20 points 4. Readability: 10 points [Reference answer] {template_code} [Student assignment] {student_code} Return: 1. A score from 0 to 100 2. A short comment Format: Score: xx Comment: xxx """ response = client.chat.completions.create( model="deepseek-reasoner", messages=[{"role": "user", "content": prompt}] ) ``` The displayed prompt is an English rendering of the source prompt; the relevant data flow and role placement are unchanged. ### Technical Analysis Student-controlled source code is interpolated into the same user-role message that contains the grading policy. The model is not given a strong trust-boundary distinction between authoritative instructions and untrusted assignment content. A student can place natural-language instructions in comments, strings, filenames, or source text that tell the model to ignore the rubric and emit a selected score. The response is then parsed as an authoritative grade without independent verification. ### Attack Path 1. A student adds prompt-injection instructions to a Python comment or string in the submitted assignment. 2. The student packages the source in a ZIP archive and sends it to the monitored mailbox. 3. `read_code` reads the attacker-controlled text. 4. `ai_grade` inserts that text directly into the grading prompt. 5. The language model may follow the embedded instructions and return an attacker-select ...[truncated 380 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Place the grading policy in a system message and explicitly identify submitted source as untrusted data, while recognizing that role separation alone is not a complete defense. - Delimit and encode the submission as data rather than presenting it as instructions. - Require schema-constrained structured output and validate that the score is an integer within the permitted range. - Use deterministic tests, static analysis, and rubric checks as the authoritative grading mechanism. - Treat AI output as advisory and require review for anomalous or high-impact results. - Add injection-focused tests containing adversarial comments and strings. - Avoid exposing reference solutions unless necessary for the grading method. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
modules/grader.py:4
Finding
Grading Module Can Execute Untrusted Student Python Without Isolation<![CDATA[ ## Vulnerability Details **File Location**: `modules/grader.py:4-10, 17-33` **Vulnerability Type**: Unsandboxed execution of attacker-controlled code **Risk Level**: Critical ### Vulnerable Code ```python def run_code(file_path): try: result = subprocess.run( ["python", file_path], capture_output=True, text=True, timeout=5 ) return result.stdout.strip() except: return None ``` ```python def grade_homework(student_dir, template_dir): student_file = None answer_file = None for f in os.listdir(student_dir): if f.endswith(".py"): student_file = os.path.join(student_dir, f) for f in os.listdir(template_dir): if f.endswith(".py"): answer_file = os.path.join(template_dir, f) if not student_file or not answer_file: return 0 student_output = run_code(student_file) answer_output = run_code(answer_file) ``` ### Technical Analysis The module locates a Python file in the extracted student directory and executes it directly using the host Python interpreter. No container, operating-system sandbox, privilege drop, filesystem restriction, environment filtering, or network restriction is applied. The five-second timeout limits only the duration of the immediate process. It does not prevent file access, network connections, secret theft, child-process creation, or persistence attempts. The current `main.py` imports `grade_homework` but uses `ai_grade` instead, so this execution path is latent rather than active in the observed main workflow. It becomes directly exploitable if `grade_homework` is invoked by another entry point or re-enabled later. ### Attack Path 1. An attacker submits a ZIP archive containing a malicious Python file. 2. The archive is extracted into the student directory. 3. A caller invokes `grade_homework` for that directory. 4. The function selects the submitted Python file. 5 ...[truncated 582 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the unused execution module if dynamic execution is not required. - Never execute submissions directly on the application host. - Use a disposable sandbox or isolated virtual machine with no host secrets and no external network access. - Run under a dedicated unprivileged identity with a read-only input mount and a minimal writable temporary directory. - Enforce CPU, memory, process-count, file-size, syscall, and execution-time limits. - Drop Linux capabilities and apply seccomp, namespace, and mandatory-access-control policies where available. - Destroy the sandbox after each submission and treat all generated output as untrusted. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
modules/excel_writer.py:4
Finding
Untrusted Grading Data Can Be Exported as Spreadsheet Formulas<![CDATA[ ## Vulnerability Details **File Location**: `modules/excel_writer.py:4-10` and `main.py:38-43` **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python results.append({ "Name": name, "Student ID": student_id, "Assignment": hw_id, "Score": score, "Comment": comment }) ``` ```python def save_to_excel(data, assignment_id): os.makedirs("data/results", exist_ok=True) path = f"data/results/assignment_{assignment_id}.xlsx" df = pd.DataFrame(data) df.to_excel(path, index=False) return path ``` The displayed column labels are English renderings of the labels in `main.py`; the underlying untrusted values and export data flow are unchanged. ### Technical Analysis The workbook contains values derived from an email attachment filename and from model-generated output. These strings are passed to pandas and the spreadsheet writer without neutralizing formula prefixes. A value beginning with `=`, `+`, `-`, or `@` may be interpreted as a formula rather than inert text by spreadsheet software. The filename parser permits broad content in the student-name field, making that field a plausible injection source. ### Attack Path 1. An attacker submits an attachment with a crafted student-name component that starts with a spreadsheet formula prefix. 2. The filename parser places the value in the result record. 3. `save_to_excel` exports the record without applying text escaping. 4. A teacher opens the generated workbook. 5. The spreadsheet application interprets the crafted cell as a formula, subject to its security configuration. ### Impact Assessment Formula execution can present deceptive hyperlinks, manipulate displayed grading information, or trigger external-data interactions supported by the spreadsheet application. The precise impact depends on the spreadsheet software and its security settings. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Treat every string exported to the workbook as untrusted. - Prefix strings beginning with `=`, `+`, `-`, or `@` with an apostrophe, or force cells to an explicit text type. - Apply sanitization to names, identifiers, comments, and all future text columns. - Validate filename-derived names against a conservative character and length policy. - Add regression tests that inspect generated cell data types and formula properties. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unpinned Dependencies and an Undeclared Runtime Package<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-2` and `modules/ai_grader.py:2` **Vulnerability Type**: Insecure and non-reproducible dependency management **Risk Level**: Low ### Vulnerable Code ```text pandas openpyxl ``` ```python from openai import OpenAI ``` ### Technical Analysis The declared packages have no version constraints or integrity hashes, so installation can resolve to different versions over time. In addition, the source imports `openai`, but that package is absent from `requirements.txt`. This creates non-reproducible deployments and may lead operators to install an arbitrary package or version manually. The reviewed files do not establish that any currently named package is malicious; the risk arises from incomplete and uncontrolled dependency resolution. ### Attack Path 1. An operator installs dependencies from the unpinned requirements file. 2. The package resolver selects whatever compatible versions are available at that time. 3. Runtime fails because the undeclared `openai` dependency is missing, or the operator installs an arbitrary version manually. 4. A compromised, incompatible, or unexpectedly changed dependency can then execute during import or normal application use. ### Impact Assessment The primary effects are supply-chain exposure, deployment inconsistency, and availability failures. If a resolved dependency is compromised, it executes with the privileges of the Skill process and can access the same local files, environment variables, and network resources. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Declare every direct runtime dependency, including the package providing `OpenAI`. - Pin reviewed versions using exact constraints. - Use a lockfile or hash-locked requirements file for reproducible installation. - Generate hashes from a trusted package index and require hash verification during deployment. - Run dependency vulnerability and license scans in continuous integration. - Update dependencies through a controlled review and testing process. ]]>
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (24)

Missing User Warnings

High
Confidence
99% confidence
Finding
This grader runs student-provided Python files without any warning, sandboxing, or security controls beyond a timeout. In the context of a grading skill, the input is explicitly adversarial or at least untrusted, so executing submissions directly can lead to arbitrary code execution on the grading machine and compromise of other students' data or platform infrastructure.

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill declares `email_user` and `email_auth_code` as inputs but provides no warning about sensitivity, no guidance on secure handling, and no indication that a mailbox authorization code will be used to authenticate to QQ Mail. Collecting email credentials without disclosure materially increases the risk of credential misuse, accidental exposure in logs, or overbroad mailbox access.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The function retrieves email attachments using `email_user` and `email_auth_code`, which indicates access to sensitive credentials and mailbox contents. In this file there is no confirmation prompt, user-facing notice, or explanatory comment/docstring disclosing that the skill will access the user's email account.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The function recursively reads all Python files from both the student and template directories and includes their full contents in a prompt sent to an external LLM API. That creates a real source-code exfiltration path: student submissions, reference solutions, embedded secrets, or proprietary grading material may be disclosed to a third party without minimization, consent, or access controls.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The natural-language prompt requires the model to grade and respond in Chinese, including fixed Chinese field labels. This enforces a specific language/locale without any user opt-in or documented justification, which is a natural-language policy concern.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code sends the student and template code to an external API but provides no user-facing warning, consent mechanism, or in-file indication that local source code leaves the system. In an educational context this is sensitive because submissions and answer keys may be confidential, and undisclosed transfer increases privacy, compliance, and trust risks.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The function logs into a real mailbox using supplied credentials/auth code and enumerates unread messages without any visible disclosure, access scoping, or consent checks. In an agent skill context, silent access to a user's inbox is sensitive because it enables collection of private email content and attachments beyond what a user may reasonably expect.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code automatically writes unseen email ZIP attachments to local storage with no validation, user notification, or consent flow. This creates a risky ingestion path for untrusted content and can expose the host to malware staging, disk abuse, or downstream processing of attacker-controlled files.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This extraction code writes files from an untrusted ZIP archive directly to disk using extractall() without validating member paths. A crafted archive can perform path traversal (Zip Slip) and overwrite files outside the intended extraction directory, potentially leading to arbitrary file overwrite and code or configuration tampering; the lack of user-facing disclosure is secondary to this more serious unsafe extraction behavior.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_code(file_path):
    try:
        result = subprocess.run(
            ["python", file_path],
            capture_output=True,
            text=True,
Confidence
96% confidence
Finding
The code executes a Python file in a subprocess based on a path discovered from the student directory, which means untrusted student code is intentionally run by the grader. Even without shell=True, this is dangerous because the executed code can read files, exfiltrate secrets, consume resources, or attack the host environment; the 5-second timeout only limits runtime and does not provide isolation.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The workflow states that ZIP attachments are downloaded, extracted, and used to generate local Excel output, but it does not warn about the filesystem risks of extracting archives or writing files locally. ZIP extraction can expose the host to malicious archive contents such as path traversal or oversized payloads, while output generation may overwrite or create sensitive files unexpectedly.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill requests QQ email credentials and processes attachments from a mailbox, but it does not warn users about the sensitivity of the authorization code or the risks of automatically downloading content from email. This can lead users to provide credentials without understanding exposure risks, and to ingest potentially malicious attachments from untrusted or spoofed senders.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The manifest states that the skill will automatically download homework from a QQ mailbox and generate an Excel file, but it does not disclose mailbox access scope, what data will be read, where attachments or outputs will be stored, or what user consent is expected. This creates a real security and privacy risk because users may provide access credentials without understanding that the skill will access potentially sensitive email content and write files to disk.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The skill extracts archives from email attachments without any visible validation or sandboxing before processing. If the unzip helper does not defend against path traversal, zip bombs, or unsafe file types, a crafted attachment could overwrite files or exhaust disk resources on the local system.

Missing User Warnings

Low
Confidence
94% confidence
Finding
The call to `save_to_excel(results, assignment_id)` persists student names, IDs, scores, and comments to a file. There is no visible warning, prompt, or comment in this file informing the user that graded student data will be stored locally.

Missing User Warnings

Low
Confidence
84% confidence
Finding
Reading an API credential from the environment is access to sensitive configuration. In this file there is no comment, docstring, or user-visible message explaining that a credential is required and will be used for external API access.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The regular expression requires filenames containing the Chinese phrase "第...次作业", which imposes a specific language/locale convention. The file provides no natural-language justification or opt-in indicating that this parser is intentionally limited to a Chinese-language regional workflow.

Missing User Warnings

Low
Confidence
93% confidence
Finding
This code writes user-provided data to an .xlsx file on disk, which is a file-write operation covered by the missing-warning rule for code files. There is no confirmation prompt, logging/print statement, or explanatory docstring/comment disclosing that the function creates output under data/results.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas
openpyxl
Confidence
98% confidence
Finding
The dependency 'pandas' is unpinned, so installations may resolve to different versions over time, reducing build reproducibility and potentially pulling in a vulnerable or breaking release unexpectedly. In a security context, lack of version pinning weakens supply-chain control even though the file itself does not prove exploitation.

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
87% confidence
Finding
The manifest references 'pandas' without a version pin, and known advisories exist for some releases, so it is impossible to verify from this file whether deployment will select an affected version. The risk is contextual and indirect here: the issue is uncertainty and potential exposure, not confirmation that a vulnerable version is in use.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas
openpyxl
Confidence
98% confidence
Finding
The dependency 'openpyxl' is unpinned, which allows future installs to fetch any currently available version and makes the environment non-reproducible. This increases supply-chain risk because a vulnerable or incompatible version could be installed without explicit review.

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
90% confidence
Finding
The manifest references 'openpyxl' without pinning a version, while known advisories affect some historical releases, so the actual security posture cannot be verified from this file alone. Because openpyxl commonly processes spreadsheet/XML content, using an affected version could matter if the skill handles untrusted files.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
The natural-language instructions and labels are written in Chinese, which effectively forces a specific language for users without any opt-in or alternative language option. The policy allows locale constraints when they are documented and justified, but this file does not state that the skill is intentionally limited to Chinese-speaking users or a China-specific environment.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
The only natural-language description is written in Chinese and presents the skill behavior without indicating language options or that the skill is specifically limited to a Chinese-language context. Under the policy, forcing a specific language or locale without opt-in can be a natural-language policy concern.

Static analysis

No suspicious patterns detected.