Back to skill

Security audit

agent-teleport

Security checks for vulnerabilities and agentic risk

Overview

This migration skill is purpose-aligned, but it transfers broad workspace data to a database and restores it by overwriting local files with weak safeguards.

Install only if you are comfortable sending the current workspace to TiDB and restoring files from that database. Review the files to be packed, avoid sensitive workspaces, protect the DSN like a password, and do not restore into an important directory without a backup or isolation.

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

T09 · Insecure Skill Coding Practices

Error
Location
run.py:145
Finding
Unsafe Archive Extraction Permits File Overwrite Through Link Entries## Vulnerability Details **File Location**: `run.py:145-150` **Vulnerability Type**: Unsafe archive extraction **Risk Level**: High **Vulnerable Code**: ```python # Extract bio = io.BytesIO(blob) with tarfile.open(fileobj=bio, mode="r:gz") as tar: # Security check for Zip Slip for member in tar.getmembers(): if os.path.isabs(member.name) or ".." in member.name: raise Exception(f"Security Error: Archive contains unsafe path {member.name}") tar.extractall(path=".") # Extract to current dir, overwriting ``` ### Technical Analysis The restore operation treats a database-supplied archive as trusted after checking only the textual names of its members. The check does not reject symbolic links, hard links, device nodes, or other special archive entries. It also does not validate link targets or resolve final destination paths before extraction. An archive can contain a link entry whose member name appears safe but whose target refers outside the current directory. Subsequent entries may then write through that link. The call to `extractall()` also deliberately overwrites existing files in the current working directory. Because the archive is retrieved using a user-supplied DSN, an attacker who controls that database—or who acquires credentials for the legitimate transfer database—can supply a crafted archive. ### Attack Path 1. The attacker creates or compromises a MySQL-compatible database accessible to the victim. 2. The attacker creates a `teleport` table containing a malicious gzip-compressed tar archive under `id=1`. 3. The archive includes a symbolic or hard link with a benign member name but an unsafe target, followed by a file written through that link. 4. The attacker gives the victim the malicious DSN, or replaces the archive in a legitimate transfer database. 5. The victim runs `run.py --action restore --dsn ...`. 6. The member-name checks pass because the unsafe destina ...[truncated 793 chars]
Remediation
## Remediation Suggestions - Extract into a newly created, permission-restricted staging directory rather than directly into the current workspace. - Permit only regular files and directories. Reject symbolic links, hard links, device nodes, FIFOs, and other special member types. - Resolve each proposed destination with `pathlib.Path.resolve()` and verify that it remains beneath the resolved staging-directory root. - Validate both member names and link targets. - Use a safe extraction filter supported by the deployed Python version, while retaining explicit validation for compatibility. - Present a manifest and require confirmation before replacing existing workspace files. - Copy validated files from staging into the destination using controlled overwrite rules rather than calling unrestricted `extractall()`. - Run restoration with the least-privileged account required for the workspace.

T09 · Insecure Skill Coding Practices

Error
Location
run.py:111
Finding
Database Connections Do Not Explicitly Enforce Verified TLS## Vulnerability Details **File Location**: `run.py:111-112` and `run.py:136-137` **Vulnerability Type**: Insecure transport configuration **Risk Level**: High **Vulnerable Code**: ```python host, port, user, password, db = parse_dsn(dsn) # Security Fix: Use standard SSL conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db) ``` The same connection pattern is used during restoration: ```python host, port, user, password, db = parse_dsn(dsn) # Security Fix: Use standard SSL conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db) ``` ### Technical Analysis Although the comments claim that standard SSL is used, the calls do not provide an SSL configuration, trusted certificate authority, or explicit certificate and hostname verification settings. A source-code comment does not activate transport encryption. The effective security therefore depends on external client and server behavior. If the database permits a connection without verified TLS, credentials and the complete workspace archive may traverse the network without authenticated encryption. Encryption without certificate and hostname validation would also remain vulnerable to an active man-in-the-middle attack. ### Attack Path 1. A user packs or restores a workspace over a network controlled or observable by an attacker. 2. The configured database endpoint accepts an unencrypted connection, or TLS is negotiated without reliable server identity verification. 3. The attacker intercepts or redirects the database connection. 4. During packing, the attacker captures database credentials and the archive BLOB. 5. During restoration, the attacker can capture the BLOB or potentially substitute malicious database responses. 6. A substituted malicious archive can compound the unsafe archive-extraction vulnerability. ### Impact Assessment Exposure of the archive can disclose source code, agen ...[truncated 557 chars]
Remediation
## Remediation Suggestions - Require TLS explicitly for every PyMySQL connection. - Configure a trusted CA bundle and enable both certificate and hostname verification. - Fail closed if authenticated TLS cannot be established; do not silently fall back to plaintext. - Document the required TiDB CA and expected transport-security settings. - Consider client-side authenticated encryption of the archive before database upload so that database or transport compromise does not reveal workspace contents. - Add integration tests that confirm plaintext endpoints and invalid certificates are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
run.py:125
Finding
Credential-Bearing DSN Is Exposed in Output and Command-Line Arguments## Vulnerability Details **File Location**: `run.py:125-130` and `run.py:164-175` **Vulnerability Type**: Sensitive credential exposure **Risk Level**: Medium **Vulnerable Code**: ```python return { "success": True, "message": f"Teleported {count} files ({size:.2f} MB) to cloud.", "teleport_code": dsn, "instruction": f"On new machine run: python skills/agent_teleport/run.py --action restore --dsn '{dsn}'" } ``` ```python if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--action", choices=["pack", "restore"], required=True) parser.add_argument("--dsn", help="Teleport code (DSN) for restore") args = parser.parse_args() if args.action == "pack": print(json.dumps(teleport_out())) elif args.action == "restore": if not args.dsn: print(json.dumps({"success": False, "error": "Missing --dsn for restore"})) else: print(json.dumps(teleport_in(args.dsn))) ``` ### Technical Analysis The DSN contains the database username and password. The pack operation returns the complete DSN in JSON and embeds it in a printable shell command. The restore interface then expects the same secret in a command-line argument. These practices can expose the credential through terminal history, captured command output, CI logs, chat transcripts, monitoring systems, shell audit logs, and process inspection. The generated command also encloses the DSN in single quotes without escaping embedded single quotes, making it unsafe as a generally valid shell command. `DESIGN.md` explicitly states that the DSN acts as the private key and that anyone possessing it can restore the archive. Consequently, accidental disclosure grants access to the migration state rather than merely exposing non-sensitive connection metadata. ### Attack Path 1. A user runs the pack operation. 2. The complete credential-bearing ...[truncated 1004 chars]
Remediation
## Remediation Suggestions - Replace the raw DSN restore code with a short-lived, single-use opaque token. - Never print database passwords or embed them in generated commands. - Accept secrets through a protected file descriptor, interactive hidden prompt, restricted configuration file, or supported secret manager rather than command-line arguments. - Ensure logs and error messages redact usernames, passwords, and tokens. - Issue a narrowly scoped database identity for each transfer and revoke it immediately after successful restoration. - Apply short expiration periods and restrict the credential to the single transfer record. - If a command must be generated, avoid including secrets and use robust argument handling rather than shell interpolation.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unpinned PyMySQL Dependency Creates Reproducibility and Supply-Chain Risk## Vulnerability Details **File Location**: `requirements.txt:1` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low **Vulnerable Code**: ```text pymysql ``` ### Technical Analysis The dependency declaration contains no version constraint or integrity hash. Each installation can therefore resolve to a different future PyMySQL release. This prevents reproducible builds and allows unreviewed upstream changes to enter the execution environment automatically. No evidence was found that the current package name is typosquatted or intentionally malicious. The finding concerns the absence of version and integrity controls rather than a confirmed malicious dependency. ### Attack Path 1. The project is installed at a later time or in a new environment. 2. The package resolver selects the newest PyMySQL release available from the configured package index. 3. If that release or package-index path has been compromised, unsafe code is installed without a corresponding project review. 4. The package is imported immediately when `run.py` starts, allowing compromised dependency code to execute with the invoking user's privileges. ### Impact Assessment A compromised dependency executes within the Python process and can access the same workspace files, environment variables, database credentials, and network permissions available to the Skill. The practical scope is therefore the invoking user's privileges and the secrets supplied to the migration process. The likelihood is lower than the directly exploitable coding flaws because no malicious dependency was identified during this audit.
Remediation
## Remediation Suggestions - Pin PyMySQL to a reviewed exact version. - Generate and retain a dependency lock file. - Require cryptographic hashes during installation, such as with a hash-locked requirements file. - Install only from an approved package index over authenticated TLS. - Use automated vulnerability and provenance checks while keeping version updates subject to review and testing.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented purpose suggests migrating agent configuration and memory, but the observed behavior expands to archiving the full workspace, provisioning a remote database, returning credential-bearing DSNs, and restoring by overwriting the current directory. This mismatch is dangerous because users may consent to a limited state transfer while the skill actually exfiltrates broader local data and can destructively modify files on restore.

Credential Access

High
Category
Privilege Escalation
Content
'.git', '.venv', 'venv', 'env', '__pycache__', 'node_modules', 
    '*.log', '*.pyc', '.DS_Store', 'google-cloud-sdk', '*.tar.gz',
    # Security: Ignore common secrets and keys
    '.env', '*.pem', '*.key', 'id_rsa', 'id_dsa', 'credentials.json', 'client_secret.json'
]

# --- Provisioner ---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
'.git', '.venv', 'venv', 'env', '__pycache__', 'node_modules', 
    '*.log', '*.pyc', '.DS_Store', 'google-cloud-sdk', '*.tar.gz',
    # Security: Ignore common secrets and keys
    '.env', '*.pem', '*.key', 'id_rsa', 'id_dsa', 'credentials.json', 'client_secret.json'
]

# --- Provisioner ---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
'.git', '.venv', 'venv', 'env', '__pycache__', 'node_modules', 
    '*.log', '*.pyc', '.DS_Store', 'google-cloud-sdk', '*.tar.gz',
    # Security: Ignore common secrets and keys
    '.env', '*.pem', '*.key', 'id_rsa', 'id_dsa', 'credentials.json', 'client_secret.json'
]

# --- Provisioner ---
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

High
Confidence
99% confidence
Finding
The restore operation extracts the remote archive directly into the current directory and may overwrite existing files without warning. In this skill context, the archive originates from a DSN-controlled remote database and can therefore replace local code, configuration, or agent memory, making destructive overwrite and persistence risks much more serious than a normal convenience restore feature.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases are broad and colloquial, so the skill could activate on ambiguous user requests like moving infrastructure or creating a backup without the user intending to package and transfer agent state. In a migration skill that handles configuration and memory, accidental activation can expose sensitive internal state or initiate a high-risk operation without sufficiently explicit consent.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The protocol invokes packing/transferring agent state without any user-facing warning that configuration and memory may contain sensitive data, secrets, conversation history, or credentials. Because this skill's purpose is migration to another machine, failing to warn and confirm materially increases the risk of unintended exfiltration or unsafe transfer of sensitive state.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares shell, environment variable, and file access capabilities implicitly but does not advertise any explicit tool scope or permissions boundary. That makes the skill harder to audit and increases the chance that an agent or user will invoke code with broader access than they reasonably expected, especially given that the skill handles local state and external networked storage.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The description does not clearly warn that pack/restore operations transfer workspace files, configuration, and memory to an external database service. In this context, omission of that warning materially increases the risk of unintentional disclosure of sensitive code, secrets, credentials, or proprietary data because the transfer target is outside the local machine.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for i in range(3):
        try:
            cmd = ["curl", "-sS", "-X", "POST", api_url, "-H", "content-type: application/json", "-d", "{}"]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            if result.returncode == 0:
                data = json.loads(result.stdout)
                dsn = data.get("instance", {}).get("connectionString")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The pack-and-upload flow sends a tarball of the current working directory to a remote TiDB instance with no interactive warning, consent, or detailed disclosure of what will be transmitted. In the context of an agent skill that migrates configuration and memory, this is especially risky because workspaces commonly contain tokens, local state, prompts, proprietary code, and other sensitive files not covered by the limited ignore list.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The code comments claim a secure SSL connection, but pymysql.connect is called without any SSL/TLS parameters or certificate validation settings. This can cause the uploaded workspace archive and database credentials to traverse the network without authenticated transport protection, enabling interception or man-in-the-middle attacks.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The restore path repeats the same issue: it states SSL is used but does not configure TLS on the database connection. Because restore retrieves the archived workspace blob over that connection, an attacker on the network path could tamper with or observe the transmitted data and potentially feed malicious archive contents to the client.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pymysql
Confidence
98% confidence
Finding
The dependency manifest specifies `pymysql` without a version pin, which makes builds non-reproducible and can cause different environments to install different releases, including vulnerable or breaking ones. In a skill that transfers agent configuration and memory between machines, dependency drift increases supply-chain risk because a fresh install may unexpectedly pull an unsafe version.

Unverifiable Dependency: pymysql has 2 known advisory(ies) (CVE-2024-36039 (PyMySQL SQL Injection vulnerability); CVE-2024-36039 (PyMySQL SQL Injection vulnerability)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding
`pymysql` has known advisories, and because the manifest does not pin a version, it is impossible to verify whether installation will resolve to a patched or affected release. This is more concerning in a migration-oriented skill that likely handles database connections and sensitive state, because a vulnerable client library could expose data access or injection-related risk depending on how it is used elsewhere in the skill.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The code reads TIDB_HOST, TIDB_USER, and TIDB_PASSWORD from the environment to construct a DSN, but provides no warning, log, or documentation in this file that credential material will be consumed. This is relevant because access to sensitive environment variables is one of the warning-triggering operations for code files.

Static analysis

No suspicious patterns detected.