Back to skill

Security audit

Privacy Protector

Security checks for vulnerabilities and agentic risk

Overview

This is a real privacy/redaction tool, but some modes send raw sensitive input to a remote or environment-selected API endpoint before redaction.

Install only if you are comfortable managing sensitive redaction workflows yourself. Use --level lite for local-only processing, verify ANONYMIZE_API_URL is unset or points to a trusted HTTPS backend before using dynamic/strict/crossborder, protect or delete saved map files because they can restore original PII, and prefer --output over --in-place when modifying files.

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

Warning
Location
modeio_redact/cli/anonymize.py:74
Finding

Unrestricted API Endpoint Override Can Exfiltrate Raw Sensitive Input

Content
View full analysis

Vulnerability Details

File Location: modeio_redact/cli/anonymize.py:74 and modeio_redact/cli/anonymize.py:265-276
Vulnerability Type: Unvalidated environment-controlled network destination
Risk Level: Medium

Vulnerable Code

python
# Backend API URL, overridable via ANONYMIZE_API_URL environment variable
URL = os.environ.get("ANONYMIZE_API_URL", "https://safety-cf.modeio.ai/api/cf/anonymize")
python
def _anonymize_via_api_provider(
    raw_input: str,
    level: str = "dynamic",
    sender_code: str = None,
    recipient_code: str = None,
    input_type: str = "text",
) -> Dict[str, Any]:
    payload = {
        "input": raw_input,
        "inputType": input_type,
        "level": level,
    }
    if sender_code:
        payload["senderCode"] = sender_code
    if recipient_code:
        payload["recipientCode"] = recipient_code
    resp = _post_with_retry(URL, headers=HEADERS, json_payload=payload)
    return resp.json()

Technical Analysis

For the dynamic, strict, and crossborder levels, the implementation sends the complete, pre-anonymization input to a remote service. This network operation is part of the declared functionality, but its destination is taken directly from the ANONYMIZE_API_URL environment variable without validating the URL scheme or hostname.

Consequently, the destination can be changed to an arbitrary server, including a plaintext HTTP endpoint. The request body may contain precisely the information the Skill is intended to protect, including personal information, document contents, passwords, access tokens, or API keys. The requests library also follows HTTP redirects by default, and the implementation does not validate the final destination against an approved origin.

This violates least-privilege and secure trust-boundary principles: API-backed anonymization needs permission to communicate with the declared backend, but ...[truncated 2107 chars]

Remediation
View remediation

Remediation Suggestions

  1. Restrict production destinations

    • Parse the endpoint with urllib.parse.urlparse.
    • Require the https scheme.
    • Allow only an explicit set of approved hostnames and ports, such as safety-cf.modeio.ai:443.
    • Reject URLs containing embedded credentials, fragments, unexpected ports, or malformed hostnames.
  2. Constrain redirects

    • Disable redirects with allow_redirects=False, or manually validate every redirect target against the same scheme and hostname allowlist.
  3. Separate production and development overrides

    • Remove unrestricted ANONYMIZE_API_URL support from normal execution.
    • If custom endpoints are required for testing, require an explicit development flag such as MODEIO_ALLOW_UNSAFE_API_OVERRIDE=1.
    • Permit only loopback destinations in development mode unless an additional explicit approval is supplied.
  4. Require informed remote-processing consent

    • Consider making lite the default.
    • Clearly warn before transmitting file contents remotely.
    • Expose the validated destination in machine-readable metadata without printing sensitive payloads.
  5. Harden tests

    • Make live API smoke tests opt-in rather than enabled by default.
    • Continue mocking network requests in normal unit tests.
    • Add tests proving that HTTP endpoints, unapproved hosts, embedded credentials, and cross-origin redirects are rejected.
  6. Minimize transmitted data

    • Where backend behavior permits, send only the content needed for detection or process documents locally.
    • Document the remote service’s retention, transport security, and data-processing boundaries.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (39)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documentation frames the skill as local/privacy-protective, but it also states that non-lite modes call a backend API, which can send sensitive input off-host. If users rely on the skill name and description without a prominent warning, they may unintentionally transmit PII externally under the assumption processing is local.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The documentation frames the skill as local/privacy-protective, but it also states that non-lite modes call a backend API, which can send sensitive input off-host. If users rely on the skill name and description without a prominent warning, they may unintentionally transmit PII externally under the assumption processing is local.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documentation frames the skill as local/privacy-protective, but it also states that non-lite modes call a backend API, which can send sensitive input off-host. If users rely on the skill name and description without a prominent warning, they may unintentionally transmit PII externally under the assumption processing is local.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
80% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · modeio_redact/detection/detect_local.py (reported line 403)May include surrounding context.

python
if lang == "cn":
        if not re.fullmatch(r"[\u4e00-\u9fa5·]{2,6}", cleaned):
            return False
        if any(token in cleaned for token in NAME_STOPWORDS_CN):
            return False
        return True

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_anonymize_contract.py (reported line 37)May include surrounding context.

python
[sys.executable, str(SCRIPT_PATH)] + args,
            capture_output=True,
            text=True,
            env=os.environ.copy(),
        )

    def test_allowlist_example_suppresses_shipped_support_email(self):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_deanonymize_contract.py (reported line 32)May include surrounding context.

python
[sys.executable, str(SCRIPT_PATH)] + args,
            capture_output=True,
            text=True,
            env=os.environ.copy(),
        )

    def test_allowlist_example_suppresses_shipped_support_email(self):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_detect_local_config.py (reported line 21)May include surrounding context.

python
[sys.executable, str(SCRIPT_PATH)] + args,
            capture_output=True,
            text=True,
            env=os.environ.copy(),
        )

    def test_allowlist_example_suppresses_shipped_support_email(self):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_detector_examples.py (reported line 21)May include surrounding context.

python
[sys.executable, str(SCRIPT_PATH)] + args,
            capture_output=True,
            text=True,
            env=os.environ.copy(),
        )

    def test_allowlist_example_suppresses_shipped_support_email(self):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_smoke_matrix_extensive.py (reported line 72)May include surrounding context.

python
[sys.executable, str(SCRIPT_PATH)] + args,
            capture_output=True,
            text=True,
            env=os.environ.copy(),
        )

    def test_allowlist_example_suppresses_shipped_support_email(self):

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises executable scripts that can read/write files, access environment variables, invoke shell commands, and make network requests, but it declares no explicit tool scope or permission boundaries. In an agent setting, that ambiguity increases the chance the skill is invoked with broader capabilities than intended, enabling data exfiltration or unsafe file operations if downstream code is permissive.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill states that dynamic, strict, and crossborder modes call a backend API, but it does not present an explicit privacy warning near usage instructions or examples. Because the processed content is likely to contain PII, silent transmission to a remote service can violate user expectations, internal policy, or regulatory controls and lead to sensitive-data disclosure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring states that non-lite levels call the Modeio API, directly contradicting the skill description that presents the capability as local/offline anonymization and detector checks. In a privacy tool, this discrepancy is security-relevant because it can mislead operators into processing regulated or confidential data remotely without informed consent.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The tool metadata and description claim local/offline anonymization behavior, but the code clearly configures a remote API endpoint via ANONYMIZE_API_URL and uses it for all non-lite levels. This can cause users to unknowingly transmit sensitive raw input, including PII, to an external service under false privacy assumptions, which is especially dangerous for a privacy-focused skill.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The requests.post call transmits the full input payload to an external endpoint, which constitutes external data exfiltration from the local environment. While network transmission itself may be intended functionality, it is dangerous here because the data can include sensitive PII and the surrounding skill context suggests local privacy-preserving processing.

Content

Scanner excerpt · modeio_redact/cli/anonymize.py (reported line 108)May include surrounding context.

python
last_exc = None
    for attempt in range(1 + MAX_RETRIES):
        try:
            resp = requests.post(url, headers=headers, json=json_payload, timeout=timeout)
            if resp.status_code in (502, 503, 504) and attempt < MAX_RETRIES:
                time.sleep(RETRY_BACKOFF * (2 ** attempt))
                continue

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The CLI selects API mode for non-lite operation and proceeds to anonymization without any user-facing warning or consent step at the point where sensitive content may be transmitted. Because this tool is marketed as a privacy protector, silent remote submission of input materially increases the chance of accidental data disclosure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill is described as supporting local anonymization and offline/privacy-preserving flows, yet this pipeline imports and instantiates a RemoteApiProvider, enabling content to be sent off-host when the selected level is not 'lite'. In a privacy-focused redaction tool, this mismatch is security-relevant because users may supply sensitive PII under the assumption it never leaves the machine.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The run method routes all non-'lite' content to RemoteApiProvider.redact, which likely transmits full input content and related metadata to an external service, but this file contains no consent gate, policy check, or disclosure mechanism. Because this skill handles PII anonymization, silent remote transmission materially increases confidentiality and compliance risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The detector's natural-language context keywords and labels include Chinese-only terms such as '电话', '身份证', '护照', and '出生' embedded directly in the skill data, which implies built-in locale-specific behavior. There is no visible indication in this file that users can choose locale coverage or that the Chinese-language bias is intentionally limited to a documented regional use case.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This module publicly exports a RemoteApiProvider even though the skill metadata emphasizes local anonymization/de-anonymization and local detector checks. In a privacy-focused skill, exposing a remote provider creates a meaningful risk that sensitive text or files could be transmitted off-device unexpectedly, undermining user expectations and potentially violating data-handling constraints.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This provider sends content to an externally supplied anonymization callable, which can route sensitive input off-device despite the skill being described as local/offline. In a privacy-focused skill, that mismatch is security-relevant because users may submit raw PII under the assumption it never leaves the host, creating a confidentiality and trust boundary violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code performs a safety-relevant file write that can overwrite the original PDF in place, including irreversible redactions and file replacement logic. While exceptions are handled, there is no confirmation prompt, user-facing log/print, or explanatory comment/docstring near the operation to disclose that the file may be modified or overwritten.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The map resolver accepts a user-supplied direct filesystem path and returns it if it exists, bypassing the intended confinement to the local mapping store directory. In a privacy/redaction skill, map files contain sensitive de-anonymization data, and accepting arbitrary paths can enable unauthorized reading or overwriting of files outside the managed store when this helper is used by higher-level restore/update flows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file describes the --in-place flag for anonymize.py as overwriting the input file, but provides no warning about the destructive nature of modifying the original file. Under the markdown-specific warning criteria, behaviors that can affect user data or system integrity should be explicitly disclosed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The deanonymize.py section states that --in-place overwrites the file input, but does not include any caution about destructive modification or preserving the original anonymized content. Markdown skill documentation should warn users when operations may alter user data irreversibly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation states that file workflows create redacted output files and a sidecar map file, but it does not clearly warn that these artifacts are written to disk and that the map data can enable reversal of anonymization. In a privacy-focused skill, omission of that warning can cause users to leave sensitive reversible metadata on local storage, backups, sync services, or shared folders without realizing the exposure.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.