Back to skill

Security audit

Dicom Anonymizer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local DICOM anonymizer, but its privacy/compliance claims are stronger than the implementation supports and could leave sensitive medical data behind.

Install only with manual review expectations. Do not rely on this as a HIPAA Safe Harbor-compliant anonymizer for releasing medical images; validate outputs with institutional privacy review, treat audit logs and returned result objects as sensitive, and pin/audit dependencies before processing real PHI.

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:67
Finding

Incomplete DICOM de-identification can leave PHI in generated output

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:67-167, scripts/main.py:397-402, and references/phi_tags.json:4-41
Vulnerability Type: Incomplete removal of sensitive medical information
Risk Level: High

Relevant Code

The executable anonymization policy is a fixed dictionary:

python
# Standard PHI DICOM Tags to anonymize
# Format: (Group, Element): (AttributeName, Action)
PHI_TAGS = {
    # Patient Information
    (0x0010, 0x0010): ("PatientName", "clear"),
    (0x0010, 0x0020): ("PatientID", "hash"),
    (0x0010, 0x0030): ("PatientBirthDate", "clear"),
    (0x0010, 0x0032): ("PatientBirthTime", "clear"),
    # ...
    (0x0038, 0x0400): ("PatientAddress", "clear"),
    (0x0038, 0x0500): ("PatientMotherAddress", "clear"),
    # ...
    (0x0020, 0x4000): ("ImageComments", "clear"),
    (0x0040, 0x2400): ("ImagingServiceRequestComments", "clear"),
}

Anonymization iterates only over this fixed table and directly accesses the root dataset:

python
# Anonymize PHI tags
tags_anonymized = 0
for tag, (tag_name, action) in self.PHI_TAGS.items():
    anon_record = self._anonymize_tag(dataset, tag, action, tag_name)
    if anon_record.action not in ["not_present", "preserved"]:
        result.anonymized_tags.append(anon_record)
        tags_anonymized += 1

The project’s separate reference list identifies sensitive attributes that are absent from the executable policy:

python
DEFAULT_PHI_TAGS = [
    "PatientName",
    "PatientID",
    "PatientBirthDate",
    "PatientSex",
    "PatientAge",
    "PatientWeight",
    "PatientAddress",
    "PatientTelephoneNumbers",
    # ...
    "StudyDate",
    "StudyTime",
    "SeriesDate",
    "SeriesTime",
    "AcquisitionDate",
    "AcquisitionTime",
    "ContentDate",
    "ContentTime",
    "InstanceCreationDate",
    "InstanceCreationTime",
    "OverlayDate",
    "CurveDate"
...[truncated 2299 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the ad hoc tag list with a reviewed implementation of the applicable DICOM PS3.15 confidentiality profile and clearly document enabled options.
  2. Recursively traverse all sequence items and apply de-identification rules to nested datasets.
  3. Cover all applicable direct identifiers, free-text attributes, person-name attributes, telephone numbers, addresses, dates, times, and UIDs.
  4. Implement a documented date strategy, such as consistent patient-specific date shifting where permitted, instead of retaining exact dates.
  5. Treat structured reports, encapsulated documents, overlays, annotations, and burned-in pixel text as separate high-risk content requiring specialized processing or rejection.
  6. Add a post-processing validator that scans the complete output recursively for prohibited tags and suspicious free text. Fail closed when residual PHI cannot be ruled out.
  7. Add regression fixtures containing PHI in root attributes, nested sequences, structured reports, private tags, and pixel annotations.
  8. Remove the “HIPAA Safe Harbor compliant” and “clinical-grade” claims until the implementation has undergone appropriate privacy, clinical, and legal validation.
  9. Require manual release review, particularly for secondary captures and images marked as containing burned-in annotations.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:274
Finding

Original PHI is retained in Python result objects

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:274-288
Vulnerability Type: Plaintext sensitive-data retention
Risk Level: Medium

Relevant Code

python
original_value = str(dataset[tag].value) if dataset[tag].value else ""

if tag_name in self.keep_tags:
    return TagAnonymization(
        tag=f"({tag[0]:04X},{tag[1]:04X})",
        attribute=tag_name,
        action="preserved",
        original_value="",
        new_value=""
    )

if action == "clear":
    new_value = "ANONYMOUS" if tag_name == "PatientName" else ""
    dataset[tag].value = new_value
    return TagAnonymization(
        tag=f"({tag[0]:04X},{tag[1]:04X})",
        attribute=tag_name,
        action="cleared",
        original_value=original_value[:50],  # Truncate for privacy
        new_value=new_value
    )

Technical Analysis

For every successfully cleared attribute, the code copies as many as 50 characters of the original value into TagAnonymization.original_value. This includes attributes such as patient names, addresses, physician names, comments, and medical history.

Truncating a sensitive value does not anonymize it. Most names, telephone numbers, identifiers, and addresses are shorter than 50 characters and may therefore be retained in full. The built-in audit writer currently records only the number of anonymized tags, but the documented Python API returns the entire AnonymizationResult, including its anonymized_tags objects. The dataclasses are also directly serializable by callers, and asdict is imported into the module.

Thus, the output DICOM may have a cleared field while the function’s associated result object still holds the original PHI.

Attack Path

  1. A caller uses the documented Python API to process a DICOM file:
    python
    result = anonymizer.anonymize_file("input.dcm", "output.dcm")
    
  2. The input contains a patient name, address, physici ...[truncated 878 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove original_value from TagAnonymization, or always leave it empty.
  2. Record only the tag identifier, attribute name, applied action, and whether the operation succeeded.
  3. If correlation is strictly required, use a purpose-specific keyed HMAC with a protected, rotated key rather than storing plaintext or an unsalted digest.
  4. Review all logging, exception, debugging, and serialization paths to ensure that dataset values cannot be emitted.
  5. Add tests asserting that patient names, IDs, addresses, comments, and other source values do not appear anywhere in returned objects or audit logs.
  6. Minimize the lifetime of source datasets and avoid unnecessary copies of sensitive strings.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Runtime dependencies are installed without exact versions or integrity hashes

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-2 and references/requirements.txt:5
Vulnerability Type: Uncontrolled dependency resolution
Risk Level: Medium

Relevant Code

Root dependency file:

text
dataclasses
pydicom

Referenced dependency file:

text
# Core DICOM library
pydicom>=2.3.0

Technical Analysis

The documented installation command resolves package names from the configured Python package index without exact version constraints or artifact hashes. The root file accepts any available release of both packages, while the reference file accepts any pydicom release at or above 2.3.0.

This makes builds non-reproducible and permits dependency behavior to change without a corresponding project review. If an upstream release, package-index account, configured mirror, or package-resolution environment is compromised, installation can introduce unreviewed code.

The dataclasses dependency is unnecessary for the documented Python 3.9+ runtime because dataclasses is included in the standard library. Installing the backport expands the supply-chain surface without a demonstrated need.

This finding does not establish that the named packages are malicious. The weakness is that dependency identity and integrity are not locked to reviewed artifacts.

Attack Path

  1. A user follows the project documentation and runs:
    bash
    pip install -r requirements.txt
    
  2. pip resolves unconstrained package versions from the user’s configured index or mirror.
  3. A compromised upstream release, package account, mirror, or dependency-resolution environment supplies an altered artifact.
  4. Package installation or later import executes code from the unreviewed artifact under the invoking user’s account.
  5. That code can access DICOM inputs, generated outputs, audit logs, and other files available to the process.

Impact Assessment

Dependency ...[truncated 475 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove dataclasses from the dependency list for supported Python 3.9+ environments.
  2. Pin pydicom to a specifically reviewed version in a lock file.
  3. Record and enforce cryptographic hashes for all downloaded artifacts, for example by using pip’s --require-hashes mode.
  4. Generate dependency locks in a controlled build process and review updates through explicit change requests.
  5. Use a trusted package index and restrict or authenticate internal mirrors.
  6. Run software-composition analysis and vulnerability scanning in CI.
  7. Build and install dependencies in an isolated environment with minimal privileges and no access to production PHI.
  8. Keep the root and reference requirement files consistent so the documented installation path cannot bypass the locked dependency policy.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (10)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module claims 'Compliant with HIPAA Safe Harbor standards,' but the implementation does not enforce a complete Safe Harbor de-identification policy and even allows user-controlled preservation of tags via keep_tags. In a medical-imaging anonymizer, overstating compliance can cause operators to trust outputs that still contain identifying metadata, creating a realistic PHI disclosure risk when datasets are shared.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill describes local script behavior that reads inputs and writes anonymized outputs, audit logs, and potentially overwrites files, but it does not declare an explicit tool scope such as permissions or allowed-tools. That omission weakens containment and review, because an agent may invoke file-writing behavior without a machine-readable restriction on where writes are permitted, increasing the chance of unintended modification or disclosure of sensitive medical data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The audit log stores linkage-oriented metadata such as pseudonyms, original_patient_id_hash, input/output paths, and per-file processing results, then writes it directly to disk without safeguards or an explicit warning at the write site. In this healthcare context, that log can become sensitive itself because deterministic hashes and linkage data may support re-identification workflows or expose internal patient-processing history if the file is shared or left on insecure storage.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

Line L180 contains the phrase "需人工检查" alongside an English translation. This introduces a language-specific instruction in the skill documentation without user opt-in or a stated locale requirement, which can violate language/locale policy expectations for generally applicable skills.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is specified with a lower bound only (pydicom>=2.3.0), which makes builds non-reproducible and allows installation of different versions over time, including newly introduced vulnerable releases. In a medical-image anonymization skill that processes untrusted DICOM files, dependency drift increases security risk because parser bugs in future or affected versions could be pulled in without review.

Content

Scanner excerpt · references/requirements.txt (reported line 5)May include surrounding context.

text
# Install with: pip install -r requirements.txt

# Core DICOM library
pydicom>=2.3.0

# Optional: For enhanced security
# cryptography>=3.0

Unverifiable Dependency: pydicom has 2 known advisory(ies) (CVE-2026-32711 (pydicom has a path traversal in FileSet/DICOMDIR ReferencedFileID allows file ac); CVE-2026-32711 (pydicom is a pure Python package for working with DICOM files. Versions 2.0.0-rc)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
89% confidence
Finding

Because pydicom is not pinned, it is impossible to determine from this manifest whether deployment will install a version affected by the cited advisories, including a reported path traversal issue. This skill's purpose—batch processing externally supplied DICOM medical images—makes parser and file-handling flaws more concerning, since crafted DICOMDIR or related inputs could potentially trigger unsafe file access during anonymization workflows.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, reducing reproducibility and potentially pulling in a newly vulnerable or incompatible release. In a medical-image anonymization skill, dependency drift is especially undesirable because reliability and secure handling of DICOM data matter.

Content

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

text
dataclasses
pydicom

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The unpinned pydicom dependency allows an arbitrary newer or older version to be installed, which can expose the skill to known vulnerabilities or breaking behavior without any code changes. Because this skill processes DICOM files from potentially external sources, using an uncontrolled parser/library version increases security risk more than in a purely internal utility.

Content

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

text
dataclasses
pydicom

Unverifiable Dependency: pydicom has 2 known advisory(ies) (CVE-2026-32711 (pydicom has a path traversal in FileSet/DICOMDIR ReferencedFileID allows file ac); CVE-2026-32711 (pydicom is a pure Python package for working with DICOM files. Versions 2.0.0-rc)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The manifest does not pin pydicom, and available advisory information indicates some versions may be affected by a path traversal issue involving DICOMDIR/FileSet handling. Since the skill handles DICOM content and may ingest untrusted medical imaging files, inability to verify that a safe version is installed is a meaningful supply-chain and input-handling risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The module docstring includes status text in Chinese only for the manual review note, which imposes a specific language fragment without offering a user choice or an English-only equivalent for that portion. This can violate language/locale policy when users are not given an opt-in or locale selection.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.