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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · run.py (reported line 22)May include surrounding context.

python
'.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 ---

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · run.py (reported line 22)May include surrounding context.

python
'.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 ---

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · run.py (reported line 22)May include surrounding context.

python
'.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 ---

Missing User Warnings

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · run.py (reported line 40)May include surrounding context.

python
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")

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
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.

Content

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

text
pymysql

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.