Back to skill

Security audit

Shift Handover Summarizer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a local EHR handover summarizer with no signs of exfiltration or persistence, but its implementation does not enforce the shift, department, or timezone boundaries it documents for sensitive clinical data.

Review before installing or using with real patient data. Treat outputs as generated from the entire supplied JSON file, not as guaranteed limited to the requested shift or department, unless you pre-filter records yourself. Avoid installing the provided requirements on modern Python unless the unnecessary dependencies are removed or locked through a trusted process.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:139
Finding
Shift and Department Boundaries Are Not Enforced<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:139-147` and `scripts/main.py:493-524` **Vulnerability Type**: Missing authorization-boundary and input-scope enforcement **Risk Level**: High ### Vulnerable Code ```python def generate_summary(self, patient_records: List[Dict]) -> ShiftSummary: """Generate shift handover summary""" patient_summaries = [] critical_count = 0 for record in patient_records: patient_summary = self._analyze_patient(record) patient_summaries.append(patient_summary) ``` ```python parser.add_argument("--records", "-r", required=True, help="Patient records JSON file path") parser.add_argument("--shift-start", "-s", required=True, help="Shift start time (ISO 8601)") parser.add_argument("--shift-end", "-e", required=True, help="Shift end time (ISO 8601)") parser.add_argument("--department", "-d", help="Department name") args = parser.parse_args() # Read patient records with open(args.records, "r", encoding="utf-8") as f: patient_records = json.load(f) # Create summarizer summarizer = ShiftHandoverSummarizer( shift_start=args.shift_start, shift_end=args.shift_end, department=args.department, include_vitals=not args.no_vitals, include_medications=not args.no_medications, include_procedures=not args.no_procedures ) # Generate summary summary = summarizer.generate_summary(patient_records) ``` ### Technical Analysis The CLI accepts shift-start, shift-end, and department restrictions, but these values are not used to filter the supplied EHR records. `generate_summary()` processes every patient object in the input and `_analyze_patient()` processes every nested record without parsing or comparing its timestamp against the requested shift period. The department argument is similarly used only as report metadata. No patient or record department field is compared with the requested department. This conflicts with the documented workflow, which states that reco ...[truncated 1422 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse `--shift-start` and `--shift-end` as timezone-aware ISO 8601 values before loading or processing clinical records. 2. Reject malformed timestamps and intervals where the end is not later than the start. 3. Parse every nested record timestamp and include only records within the explicitly documented boundary semantics. 4. Define whether the shift end is inclusive or exclusive and apply that rule consistently. 5. Require or identify a canonical department field and filter patients or records against it when `--department` is provided. 6. Reject records with missing or malformed timestamps instead of silently including them; report excluded-record counts without exposing unnecessary patient information. 7. Avoid including a patient in the output if none of that patient's records fall within the selected scope, unless explicitly required by the product specification. 8. Add tests covering mixed shifts, mixed departments, exact boundary timestamps, malformed timestamps, daylight-saving transitions, and timezone-offset conversions. 9. Clearly distinguish the requested scope from the validated scope in output metadata. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:493
Finding
Timezone Validation and Documented UTC Handling Are Missing<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:493-510` **Related Documentation**: `SKILL.md:25-28` **Vulnerability Type**: Unvalidated and ambiguous time input **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--records", "-r", required=True, help="Patient records JSON file path") parser.add_argument("--shift-start", "-s", required=True, help="Shift start time (ISO 8601)") parser.add_argument("--shift-end", "-e", required=True, help="Shift end time (ISO 8601)") parser.add_argument("--department", "-d", help="Department name") parser.add_argument("--output", "-o", help="Output file path") parser.add_argument("--no-vitals", action="store_true", help="Exclude vital signs") parser.add_argument("--no-medications", action="store_true", help="Exclude medication info") parser.add_argument("--no-procedures", action="store_true", help="Exclude procedure info") args = parser.parse_args() # Read patient records with open(args.records, "r", encoding="utf-8") as f: patient_records = json.load(f) # Create summarizer summarizer = ShiftHandoverSummarizer( shift_start=args.shift_start, shift_end=args.shift_end, department=args.department, ``` The documented behavior is: ```markdown If `--shift-start` or `--shift-end` lacks a timezone offset (e.g., `2026-02-06T00:00:00` without `Z` or `+HH:MM`), emit a warning: "Shift times appear to lack a timezone offset. Assuming UTC. Specify timezone explicitly (e.g., `2026-02-06T00:00:00+08:00`) to avoid incorrect event filtering." ``` ### Technical Analysis The shift arguments are accepted as arbitrary strings. The implementation does not verify ISO 8601 syntax, check for timezone offsets, normalize `Z` or explicit offsets, warn about naive timestamps, or apply the documented UTC assumption. The values are subsequently presented as the report's shift period. This allows malformed or ambiguous time data to be represented as a successfully generated handover. The risk ...[truncated 1201 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse both shift arguments immediately after argument parsing with a strict ISO 8601 parser. 2. Detect a trailing `Z` and normalize it to UTC; preserve and correctly convert explicit numeric offsets. 3. If a timestamp lacks an offset, either reject it or emit the exact documented warning and explicitly attach UTC. 4. Reject impossible dates, malformed values, and reversed or zero-length intervals. 5. Store normalized timestamps internally as timezone-aware `datetime` objects rather than unchecked strings. 6. Serialize normalized ISO 8601 values, including their offsets, in the output metadata. 7. Use the parsed timestamps to enforce record filtering. 8. Add automated tests for `Z`, positive and negative offsets, naive timestamps, malformed strings, and daylight-saving boundaries. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Unnecessary Unpinned Dependencies Shadow Standard-Library Modules<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-2` **Vulnerability Type**: Unnecessary and unconstrained third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```text dataclasses enum ``` The application imports modules with the same names: ```python from dataclasses import dataclass, field, asdict from enum import Enum ``` ### Technical Analysis Supported modern Python releases include `dataclasses` and `enum` in the standard library. Listing packages with these names in `requirements.txt` causes package installers to resolve mutable third-party distributions unnecessarily. Neither dependency has a version constraint or integrity hash. This exposes installation to future package changes and avoidable supply-chain behavior. A third-party `enum` package may also shadow or conflict with Python's standard-library `enum` module, creating unpredictable import behavior. This finding does not establish that the currently published packages are malicious. The vulnerability is the unnecessary, unpinned supply-chain exposure introduced by the dependency manifest. ### Attack Path 1. An operator follows the normal installation workflow and runs `pip install -r requirements.txt`. 2. The package installer contacts its configured package index and resolves unconstrained releases named `dataclasses` and `enum`. 3. Package-controlled build or installation logic executes with the privileges of the operator or build environment. 4. A compromised release, untrusted package index, dependency-confusion condition, or incompatible shadowing package can affect the environment before the summarizer runs. 5. The installed package may execute unwanted installation behavior or alter which module implementation the application imports. ### Impact Assessment The obtainable privileges depend on the installation context. Malicious package installation logic would generally execute with the same privileges as the user, CI runner, con ...[truncated 340 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove both `dataclasses` and `enum` from `requirements.txt` when using a modern supported Python version. 2. Declare the minimum supported Python version in project metadata and documentation. 3. If legacy Python support is essential, use only the canonical conditional backport required for that version. 4. Pin any genuinely required third-party dependency to a reviewed version and use cryptographic hashes with `pip --require-hashes`. 5. Generate and review a lock file through a controlled dependency-management process. 6. Install dependencies from an approved package index and prevent fallback to untrusted indexes. 7. Run dependency installation in an isolated, least-privileged build environment without production credentials. 8. Add dependency scanning and standard-library shadowing checks to CI. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares executable usage of a local script and output file handling, implying file read/write capability, but it does not declare any explicit tool scope such as permissions or allowed-tools. In an agent environment, this can cause the skill to run with broader-than-expected filesystem access, increasing the chance of unintended access to sensitive EHR data or writing summaries to unsafe locations.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The initializer hard-codes `language: str = "zh-CN"`, which imposes a specific language/locale by default. Under the policy rules, forcing a locale without offering user choice or documenting a justified regional constraint is a natural-language policy violation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
dataclasses
enum
Confidence
60% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
dataclasses
enum
Confidence
60% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Static analysis

No suspicious patterns detected.