Back to skill

Security audit

Easydoc Mask

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its EasyLink document-masking purpose, but its helper can send medical records and the API key to an arbitrary overridden endpoint without validation or clear warning.

Install only if you trust EasyLink for the documents you plan to process and have authority to upload them. Avoid using --base-url unless you have independently verified the destination and credential handling; the safer posture is to remove or lock that option to the documented EasyLink HTTPS host before use with real medical records.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/easydoc_mask.py:87
Finding

Unrestricted API Endpoint Override Can Exfiltrate API Credentials and Unredacted Medical Records

Content
View full analysis

Vulnerability Details

File Location: scripts/easydoc_mask.py:87-91, scripts/easydoc_mask.py:220-239, and scripts/easydoc_mask.py:428-435
Vulnerability Type: Unvalidated security-sensitive endpoint override
Risk Level: High

Vulnerable Code

python
parser.add_argument(
    "--base-url",
    default="",
    help="Optional base URL override.",
)
python
def submit_task(
    api_key: str,
    base_url: str,
    file_paths: List[Path],
    custom_fields: List[str],
    timeout: int = 60,
) -> Dict:
    url = f"{base_url.rstrip('/')}{SUBMIT_PATH}"

    form_fields: List[Tuple[str, str]] = [("mode", MODE)]
    fields_to_use = custom_fields if custom_fields else DEFAULT_MASK_FIELDS
    properties = {field: {"type": "string"} for field in fields_to_use}
    schema = json.dumps({"properties": properties}, ensure_ascii=False)
    form_fields.append(("json_schema", schema))

    payload, boundary = encode_multipart(
        fields=form_fields,
        files=[(FILE_FIELD, file_path) for file_path in file_paths],
    )
    headers = {
        "api-key": api_key,
        "Content-Type": f"multipart/form-data; boundary={boundary}",
    }
    return http_json("POST", url, headers=headers, body=payload, timeout=timeout)
python
api_key = resolve_api_key(args.api_key)
base_url = args.base_url.strip() or BASE_URL
file_paths = [Path(p).expanduser().resolve() for p in args.file]

if file_paths:
    validate_files(file_paths, skip_local_checks=args.skip_local_checks)

Technical Analysis

The command-line --base-url value is used directly to construct submission and polling URLs. The implementation does not validate the URL scheme, hostname, port, user-information component, query, or fragment.

The resulting POST request contains both:

  1. The EasyLink API credential in the api-key request header.
  2. Complete source documents in the multi ...[truncated 2211 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove --base-url and always use the documented https://api.easylink-ai.com endpoint if alternate deployments are not a required feature.
  2. If endpoint configurability is operationally necessary, enforce an explicit allowlist of trusted HTTPS origins. Validate the parsed URL rather than relying on string-prefix comparisons.
  3. Require:
    • Scheme exactly equal to https.
    • Hostname exactly equal to an approved host.
    • An approved port, normally 443.
    • No URL user-information, query, or fragment components.
  4. Bind credentials to their intended origin. Never send the production EasyLink key to development, proxy, or custom endpoints; require separate credentials for each explicitly trusted deployment.
  5. Display the destination origin and obtain explicit confirmation before transmitting unredacted medical documents when any non-default deployment is supported.
  6. Add automated tests proving that HTTP URLs, subdomain tricks, embedded credentials, lookalike domains, redirects to unapproved origins, and arbitrary external hosts are rejected.
  7. Configure redirect handling so authentication headers and upload bodies are never forwarded to an origin outside the allowlist.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes capabilities that can access environment secrets, read local files, write results, and transmit data over the network, but it does not declare any explicit tool scope or permission boundaries. That weakens least-privilege controls and makes it easier for an agent to overreach, especially because the workflow handles sensitive medical documents and API keys.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill is explicitly designed to upload EMR and other potentially sensitive documents to a third-party API, but it does not prominently warn users about external data transfer, privacy implications, retention, or jurisdictional handling. In the medical-record context, that omission is significant because users may unknowingly send regulated or highly sensitive data off-platform.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
94% confidence
Finding

This command sends document contents to an external HTTPS endpoint for masking. External transmission is expected for the feature, but in the context of medical records it is still security-relevant because sensitive files and associated metadata leave the local trust boundary and are processed by a third party.

Content

Scanner excerpt · SKILL.md (reported line 88)May include surrounding context.

Submit and poll:

bash
curl -X POST "https://api.easylink-ai.com/v1/easydoc/mask" \
  -H "api-key: $EASYLINK_API_KEY" \
  -F "files=@record.pdf" \
  -F "mode=emr-mask"

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This example not only uploads a document externally but also includes custom masking schema that may reveal which sensitive fields are present or of interest. In an EMR context, transmitting both file content and sensitivity-related metadata to a third party expands privacy exposure even if the endpoint is legitimate.

Content

Scanner excerpt · SKILL.md (reported line 97)May include surrounding context.

With custom fields:

bash
curl -X POST "https://api.easylink-ai.com/v1/easydoc/mask" \
  -H "api-key: $EASYLINK_API_KEY" \
  -F "files=@record.pdf" \
  -F "mode=emr-mask" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documentation instructs users to upload EMR and other sensitive medical documents to a third-party remote API but does not clearly warn that the files leave the local environment for external processing. In the context of medical records, this omission is dangerous because users may unknowingly transmit PHI/PII to an external processor without evaluating consent, regulatory, retention, residency, or vendor-risk requirements.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
94% confidence
Finding

This example sends a local file directly to an external HTTPS endpoint, which is expected behavior for the API but still represents real external transmission of sensitive document contents. Because the skill is specifically for EMR masking, the transmitted data likely contains PHI/PII, making the privacy and compliance risk substantial if users are not clearly informed and authorized.

Content

Scanner excerpt · references/easydoc-mask-api.md (reported line 34)May include surrounding context.

Submit with default masking:

bash
curl -X POST "https://api.easylink-ai.com/v1/easydoc/mask" \
  -H "api-key: your_apikey_here" \
  -F "files=@record.pdf" \
  -F "mode=emr-mask"

External Transmission

Medium
Category
Data Exfiltration
Confidence
94% confidence
Finding

This example transmits a record file and custom masking schema to an external vendor endpoint. While functionally necessary for the feature, it is risky in this context because medical records and associated schema choices may reveal sensitive categories of information and are being sent off-platform without any adjacent warning or governance guidance.

Content

Scanner excerpt · references/easydoc-mask-api.md (reported line 43)May include surrounding context.

Submit with custom fields:

bash
curl -X POST "https://api.easylink-ai.com/v1/easydoc/mask" \
  -H "api-key: your_apikey_here" \
  -F "files=@record.pdf" \
  -F "mode=emr-mask" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 107)May include surrounding context.

GET /v1/easydoc/mask/{task_id}

bash
curl -X GET "https://api.easylink-ai.com/v1/easydoc/mask/b_mask_xxx" \
  -H "api-key: your_apikey_here"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/easydoc-mask-api.md (reported line 67)May include surrounding context.

GET /v1/easydoc/mask/{task_id}

bash
curl -X GET "https://api.easylink-ai.com/v1/easydoc/mask/b_mask_xxx" \
  -H "api-key: your_apikey_here"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This script uploads local medical-record files to a third-party remote API, but it does not present an explicit user-facing warning or confirmation at the point of transmission that sensitive document contents will leave the local environment. In a healthcare/EMR context, that omission can cause inadvertent disclosure of highly sensitive personal and medical data, especially if the tool is invoked by another agent or automation layer where the user may not realize files are being exfiltrated to an external service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The text states 'Single platform only (CN/EasyLink)' and hard-codes the China-based endpoint, which is a locale/platform restriction expressed in natural language. The file does not offer a locale choice or explain why this regional limitation is required, so it may violate the language/locale policy criterion.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.