Back to skill

Security audit

Teable

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Teable API management skill, but it grants broad live data-changing authority with weak safety guardrails around deletion, tokens, and custom endpoints.

Install only if you are comfortable giving the skill a Teable token with the exact permissions it can use. Prefer a least-privilege token, avoid storing it in shell startup files, use only trusted HTTPS Teable URLs, and treat delete, trash reset, collaborator, invitation, and plugin commands as live administrative actions that should be reviewed before execution.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/teable_base.py:18
Finding
Bearer Token Disclosure and SSRF Through Insufficient Endpoint Validation<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/teable_base.py:18-55, 105-123` - `scripts/teable_record.py:18-58, 115-139` - `scripts/teable_dashboard.py:17-36, 47-62` - `scripts/teable_space.py:18-39, 50-65` - `scripts/teable_table.py:17-36, 47-62` - `scripts/teable_trash.py:17-36, 47-62` **Vulnerability Type**: Insufficient URL validation, plaintext credential transmission, and server-side request forgery **Risk Level**: High ### Vulnerable Code The following representative implementation appears in `scripts/teable_base.py` and is substantially duplicated across all six clients: ```python ALLOWED_SCHEMES = ["https", "http"] def validate_url(url: str) -> str: """ Validate URL to prevent SSRF and credential exfiltration. Args: url: URL to validate Returns: Validated URL Raises: ValueError: If URL is invalid or potentially malicious """ if not url: return url try: parsed = urlparse(url) if parsed.scheme.lower() not in ALLOWED_SCHEMES: raise ValueError( f"Invalid URL scheme: '{parsed.scheme}'. " f"Only {ALLOWED_SCHEMES} are allowed." ) if not parsed.netloc: raise ValueError(f"Invalid URL: missing domain in '{url}'") if parsed.scheme.lower() == "http": print( "WARNING: Using HTTP instead of HTTPS. " "Your API key will be transmitted in plaintext!", file=sys.stderr ) return url.rstrip("/") except Exception as e: raise ValueError(f"Invalid TEABLE_URL '{url}': {e}") ``` The validated URL is then combined with the API path and used in a session that always contains the bearer token: ```python raw_url = base_url or os.getenv("TEABLE_URL") or DEFAULT_BASE_URL self.base_url = validate_url(raw_url) self.api_key = api_key or ...[truncated 3791 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require HTTPS for all authenticated requests: ```python ALLOWED_SCHEMES = {"https"} ``` 2. If plaintext HTTP is required for local development, gate it behind an explicit unsafe option and do not attach the bearer token automatically. 3. Use an administrator-managed allowlist for permitted Teable hosts. Do not treat any syntactically valid HTTP or HTTPS URL as trusted. 4. Reject URLs containing embedded user information, unexpected ports, fragments, or malformed hostnames. 5. Resolve the hostname before sending credentials and reject loopback, private, link-local, multicast, reserved, and unspecified IP addresses unless a specific self-hosted deployment explicitly allows them. 6. Revalidate every resolved destination and redirect target. Prefer disabling redirects for authenticated API requests unless redirects are required: ```python response = self.session.request( method, url, allow_redirects=False, timeout=(5, 30), **kwargs ) ``` 7. Attach the `Authorization` header only after validating the final destination rather than storing it in a session that may be reused for arbitrary URLs. 8. Use separate configuration for trusted self-hosted deployments and document that adding a host grants it access to the API token. 9. Add security tests covering attacker-controlled hosts, HTTP URLs, IPv4 and IPv6 loopback addresses, private ranges, link-local addresses, hostname resolution to private IPs, and redirects to untrusted origins. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/teable_base.py:62
Finding
Output Directory Restriction Can Be Bypassed Through Prefix Confusion and Symlinks<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/teable_base.py:62-93, 447-450` - `scripts/teable_record.py:65-98, 410-414` **Vulnerability Type**: Improper path containment validation and arbitrary file overwrite **Risk Level**: Medium ### Vulnerable Code The complete validation function in `scripts/teable_base.py` is: ```python def validate_output_path(path: str, base_dir: Optional[str] = None) -> str: """ Validate output file path to prevent path traversal attacks. Args: path: Output file path base_dir: Base directory (defaults to current working directory) Returns: Absolute path if valid Raises: ValueError: If path attempts directory traversal """ if not path: raise ValueError("Output path cannot be empty") if base_dir is None: base_dir = os.getcwd() abs_base = os.path.abspath(base_dir) abs_path = os.path.abspath(path) if not abs_path.startswith(abs_base): raise ValueError( f"Security error: Output path '{path}' is outside allowed directory. " f"Files can only be written to '{abs_base}' or its subdirectories." ) return abs_path ``` The validated path is opened in write mode during base export: ```python elif args.command == "export": data = client.export_base(args.base_id, include_data=not args.no_data) # Validate output path for security safe_path = validate_output_path(args.output) with open(safe_path, "wb") as f: f.write(data) print(f"Exported to {safe_path}") ``` The same flawed validation is used for record output in `scripts/teable_record.py`: ```python if args.output: # Validate output path for security safe_path = validate_output_path(args.output) with open(safe_path, "w", encoding="utf-8") as f: f.write(output) print(f"Saved to {safe_path}") ``` ### Technical Analysis The code uses a string-prefi ...[truncated 2591 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace string-prefix comparison with a filesystem-aware containment check: ```python from pathlib import Path def validate_output_path(path: str, base_dir: Optional[str] = None) -> str: if not path: raise ValueError("Output path cannot be empty") base = Path(base_dir or os.getcwd()).resolve(strict=True) target = Path(path).resolve(strict=False) try: target.relative_to(base) except ValueError: raise ValueError( f"Output path '{path}' is outside the allowed directory '{base}'" ) return str(target) ``` 2. Alternatively, use `os.path.commonpath()` rather than `startswith()`: ```python if os.path.commonpath([abs_base, abs_path]) != abs_base: raise ValueError("Output path is outside the allowed directory") ``` 3. Resolve and reject symlink components before opening the destination. Where supported, use directory file descriptors and `O_NOFOLLOW` to reduce time-of-check/time-of-use and symlink races. 4. If overwriting is unnecessary, create output files exclusively with mode `"x"` or `O_EXCL`. 5. Restrict output to a dedicated export directory with controlled permissions rather than the caller's current working directory. 6. Add tests for sibling directories with common prefixes, `..` traversal, absolute paths, symlinked files, symlinked directories, and paths changed between validation and opening. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Rogue AgentSelf-Modification, Session Persistence
Findings (29)

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
Installation

### Prerequisites

Install the required Python package:

```bash
pipx install requests
# or globally
pip3 install requests
```

### Environment Variables

**Required**: Set the `TEABLE_API_KEY` environment variable before using any scripts:

```bash
# Temporary (current shell session)
export TEABLE_API_KEY="your_personal_access_token_here"

# Permanent (add to ~/.bashrc or ~/.zshrc)
echo 'export TEABLE_API_KEY="your_personal_access_token_here"' >> ~/.bashrc
source ~/.bashrc
```

**Getting Your Teable API Token**:
1. Log in to your Teable instance
2. Go to Settings → Access Token
3. Create a new Personal Access Token
4. Copy and save the token (shown only once)

**Optional**: For self-hosted Teable instances, set `TEABLE_URL`:

```bash
export TEABLE_URL="https://your-teable-instance.com"
# Default: https://app.teable.ai
```

## Usage

### Command-Line Scripts

All scripts are located in the `scripts/` directory:

```bash
# Record operations
python3 scripts/teable_record.
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Credential Access

High
Category
Privilege Escalation
Content
**Getting Your Teable API Token**:
1. Log in to your Teable instance
2. Go to Settings → Access Token
3. Create a new Personal Access Token
4. Copy and save the token (shown only once)
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
**Getting Your Teable API Token**:
1. Log in to your Teable instance
2. Go to Settings → Access Token
3. Create a new Personal Access Token
4. Copy and save the token (shown only once)
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
**Getting Your Teable API Token**:
1. Log in to your Teable instance
2. Go to Settings → Access Token
3. Create a new Personal Access Token
4. Copy and save the token (shown only once)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ae1

High
Category
analysis-evasion
Content
python3 scripts/teable_base.py list --space-id <spaceId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/teable_base.py list --space-id <spaceId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/teable_base.py list --space-id <spaceId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/teable_base.py list --space-id <spaceId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/teable_base.py list --space-id <spaceId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README advertises full CRUD operations across many resource types, including destructive actions, but does not warn users that commands may modify or delete live Teable data. In an agent skill context, this increases the chance of accidental execution of state-changing operations without adequate user awareness or confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Listing "permanent delete" as supported functionality without an explicit irreversibility warning can lead users or downstream agents to perform data-destroying actions without understanding the consequences. In an automation setting, this is especially risky because destructive capabilities may be invoked programmatically and at scale.

Session Persistence

Medium
Category
Rogue Agent
Content
# Temporary (current shell session)
export TEABLE_API_KEY="your_personal_access_token_here"

# Permanent (add to ~/.bashrc or ~/.zshrc)
echo 'export TEABLE_API_KEY="your_personal_access_token_here"' >> ~/.bashrc
source ~/.bashrc
```
Confidence
95% confidence
Finding
Persisting an API key via ~/.bashrc creates session persistence for a secret, causing the credential to be reloaded automatically in every shell. While not malware persistence, it still increases exposure of a sensitive token and can broaden the blast radius if the account or workstation is compromised.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The instructions tell users to persist a personal access token in shell startup files, which can leave long-lived credentials stored in plaintext on disk and automatically loaded into future sessions. This raises the risk of token disclosure through local compromise, shell history mistakes, backups, dotfile syncing, or accidental sharing of configuration files.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill documents destructive operations such as delete, reset, and permanent delete with no explicit warning, confirmation step, or note about irreversible data loss. In an automation context, this increases the chance of accidental or scripted mass deletion of records, bases, dashboards, or trash contents.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This markdown file includes restore, trash reset, and permanent deletion examples, including a 'Permanently delete' command, but does not provide a user warning about the impact on user data or irreversibility. For markdown files, examples that affect data integrity should clearly disclose destructive behavior so users are less likely to run them casually.

External Transmission

Medium
Category
Data Exfiltration
Content
#### Method 3: Direct API Call

```bash
curl -X POST 'https://app.teable.ai/api/table/tblXXX/record' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The delete_base method performs a DELETE request, including a permanent deletion mode, but the code provides no confirmation step or pre-action warning before carrying out this destructive operation. The later success message is post-action only, so users are not warned before data may be irreversibly removed.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code exposes a delete operation that irreversibly removes a dashboard, but the deletion path has no confirmation prompt, warning comment, or other user disclosure near the operation itself. Although the CLI later prints success/failure, that happens only after execution and does not warn the user beforehand.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Removing an installed plugin is a potentially destructive action, yet this function issues the DELETE request without any confirmation prompt or pre-action disclosure. The later success message is not sufficient because it appears only after the removal has already occurred.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The CLI delete path immediately parses record IDs and calls the deletion API, then only prints a success/failure message after the destructive action has already occurred. Although the command name implies deletion, there is no confirmation prompt or explicit user-facing warning before the irreversible operation executes.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The code claims to validate the URL to prevent SSRF and credential exfiltration, but it only checks that the scheme is HTTP/HTTPS and that a host is present. An attacker who can influence TEABLE_URL or the base_url argument can direct authenticated requests, including the Bearer API key, to an arbitrary external or internal host, causing credential leakage or SSRF against reachable services.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The script advertises 'security validations', but its URL validation still allows arbitrary user-controlled HTTP and HTTPS endpoints via TEABLE_URL. Because the client always attaches a bearer token, an attacker who can influence that environment variable can redirect requests to an attacker-controlled server or cause plaintext transmission over HTTP, leading to credential disclosure and misuse.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The document instructs users to export a personal access token and later suggests echoing the API key for troubleshooting, but it does not warn that the token is sensitive and should not be shared, logged, or exposed in shell history/screenshots. Markdown guidance that involves credentials should disclose privacy and security implications.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The FAQ entry contains the Chinese word "权衡" inside otherwise English documentation. This creates an inconsistent language experience and effectively forces a locale-specific term on readers without offering any language choice or documenting that the content is region-specific.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.28.0
Confidence
98% confidence
Finding
The dependency is specified as `requests>=2.28.0`, which allows any future release to be installed and makes builds non-reproducible. This increases supply-chain risk because a vulnerable or breaking upstream version could be pulled in later without review, and it also makes it impossible to reliably verify which version is deployed.

Static analysis

No suspicious patterns detected.