Back to skill

Security audit

Feishu Bitable

Security checks for vulnerabilities and agentic risk

Overview

This Feishu Bitable skill is mostly purpose-aligned, but it needs Review because it can directly change or delete live business data and has weak safeguards around Feishu credentials and cached tokens.

Install only if you trust the environment where it will run and can scope the Feishu app to the minimum tables and permissions needed. Treat insert, update, and delete commands as production data changes, verify records with select/describe first, avoid filter-based deletes unless you intentionally bound them, and do not set FEISHU_API_HOST except to a trusted Feishu endpoint. On shared machines, review or disable the token cache because it stores a bearer token on disk.

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/feishu_bitable.py:31
Finding

Unrestricted API host override enables credential, token, and Bitable data redirection

Content
View full analysis

Vulnerability Details

File Location: scripts/feishu_bitable.py:31-37, 88-104, 108-126
Vulnerability Type: Arbitrary network destination for sensitive authentication material and Bitable data
Risk Level: High

Vulnerable Code

python
DEFAULT_HOST = os.getenv("FEISHU_API_HOST", "https://open.feishu.cn")
DEFAULT_CACHE = os.getenv(
    "FEISHU_TOKEN_CACHE",
    str(Path.home() / ".cache" / "openclaw" / "feishu_tenant_token.json")
)

TOKEN_URL = f"{DEFAULT_HOST}/open-apis/auth/v3/tenant_access_token/internal"
python
def get_tenant_token() -> str:
    app_id = os.getenv("FEISHU_APP_ID")
    app_secret = os.getenv("FEISHU_APP_SECRET")
    if not app_id or not app_secret:
        raise RuntimeError("Missing env: FEISHU_APP_ID / FEISHU_APP_SECRET")

    cached = _load_cached_token(DEFAULT_CACHE)
    if cached:
        log_debug("Using cached token")
        return cached

    resp = _http_json("POST", TOKEN_URL, headers={}, body={"app_id": app_id, "app_secret": app_secret})
    if resp.get("code") != 0:
        raise RuntimeError(f"Token error: {resp}")
    token = resp["tenant_access_token"]
    expire = resp.get("expire", 3600)
    _save_cached_token(DEFAULT_CACHE, token, expire)
    log_debug("Token refreshed")
    return token
python
def _api_get(url: str) -> Dict[str, Any]:
    token = get_tenant_token()
    return _http_json("GET", url, headers={"Authorization": f"Bearer {token}"})


def _api_post(url: str, body: Dict[str, Any]) -> Dict[str, Any]:
    token = get_tenant_token()
    return _http_json("POST", url, headers={"Authorization": f"Bearer {token}"}, body=body)


def _api_put(url: str, body: Dict[str, Any]) -> Dict[str, Any]:
    token = get_tenant_token()
    return _http_json("PUT", url, headers={"Authorization": f"Bearer {token}"}, body=body)


def _api_delete(url: str) -> Dict[str, Any]:
    token = get_tenant_token()
    return
...[truncated 2869 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove FEISHU_API_HOST configurability if alternate endpoints are not strictly required.
  2. If configurability is required, parse the value with a standard URL parser and require HTTPS.
  3. Allowlist exact trusted Feishu API hostnames rather than relying on suffix matching. Reject user information, fragments, unexpected ports, raw IP addresses, and deceptive hostname suffixes.
  4. Use independently validated, fixed origins for authentication and Bitable API traffic.
  5. Prevent credentials and Authorization headers from being forwarded to a different origin during redirects. Prefer disabling redirects for authenticated requests or validating every redirect target.
  6. Reject cleartext HTTP endpoints and fail closed when destination validation fails.
  7. Document the accepted endpoint allowlist and treat any endpoint change as a security-sensitive configuration operation.
  8. Apply minimum Feishu application scopes so that compromise of credentials does not grant unnecessary write or delete permissions.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu_bitable.py:32
Finding

Tenant access token is cached without enforced restrictive permissions or symlink protection

Content
View full analysis

Vulnerability Details

File Location: scripts/feishu_bitable.py:32-35, 75-85
Vulnerability Type: Insecure plaintext storage of an authentication bearer token
Risk Level: Medium

Vulnerable Code

python
DEFAULT_CACHE = os.getenv(
    "FEISHU_TOKEN_CACHE",
    str(Path.home() / ".cache" / "openclaw" / "feishu_tenant_token.json")
)
python
def _save_cached_token(cache_path: str, token: str, expire_seconds: int) -> None:
    p = Path(cache_path)
    p.parent.mkdir(parents=True, exist_ok=True)
    obj = {
        "tenant_access_token": token,
        "expires_at": int(time.time()) + int(expire_seconds),
    }
    p.write_text(json.dumps(obj, ensure_ascii=False), "utf-8")

Technical Analysis

The tenant bearer token is persisted as plaintext JSON. The implementation does not explicitly create the cache directory with mode 0700 or the cache file with mode 0600. Instead, resulting permissions depend on the process umask and any pre-existing directory or file.

Path.write_text() also follows symbolic links and performs no ownership, file-type, or permission validation. The cache location can be changed through FEISHU_TOKEN_CACHE, but the path is not constrained to a trusted, user-owned directory.

In a shared environment, a permissive umask or pre-existing cache file can make the bearer token readable by other local users. If an attacker can prepare the cache path or influence its configuration, a symbolic link can redirect the token write to another accessible location.

Attack Path

  1. An attacker identifies a shared or permissively accessible cache directory, influences FEISHU_TOKEN_CACHE, or prepares the selected cache file as a symbolic link.
  2. The Skill authenticates to Feishu after finding no valid cached token.
  3. _save_cached_token() writes the newly issued tenant access token through Path.write_text() without enforcing secure permissions or rejecting ...[truncated 731 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create the cache directory with mode 0700 and verify that it is owned by the current user.
  2. Create the token file atomically with mode 0600, using low-level file APIs such as os.open() with appropriate creation flags.
  3. Use O_NOFOLLOW where supported and reject symbolic links, non-regular files, and files not owned by the current user.
  4. Validate permissions and ownership before reading an existing cache file; reject files accessible to group or other users.
  5. Write to a securely created temporary file in the same trusted directory and atomically replace the final cache file.
  6. Constrain FEISHU_TOKEN_CACHE to a trusted user-owned cache directory, or remove arbitrary path configurability if it is unnecessary.
  7. Prefer an operating-system credential store or keyring instead of plaintext token storage where available.
  8. Delete expired tokens and avoid including token values in logs or exception messages.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The delete command can remove single, multiple, or filter-matched records immediately with no confirmation prompt, dry-run mode, or safeguard against broad matches. In an agent or automation context, malformed input, prompt injection, or operator error could trigger irreversible bulk deletion of business data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill documents irreversible delete operations against a remote Feishu Bitable without any safety warning, confirmation step, or guidance to verify target record IDs first. In an agent setting, this increases the chance of accidental destructive actions and data loss, especially because the interface is framed as a convenient SQL-like tool for direct remote modification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script stores a credential-derived tenant access token on disk in a predictable cache location without setting restrictive file permissions or warning the user. On multi-user systems or misconfigured environments, another local user or process could read the token and use it to access Feishu APIs with the application's privileges until expiration.

Content

No source excerpt is available for this finding.

Tainted flow: 'obj' from pathlib.Path.read_text (line 68, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/feishu_bitable.py (reported line 85)May include surrounding context.

python
"tenant_access_token": token,
        "expires_at": int(time.time()) + int(expire_seconds),
    }
    p.write_text(json.dumps(obj, ensure_ascii=False), "utf-8")


def get_tenant_token() -> str:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The insert and update examples encourage direct writes to a live remote data source without clearly warning that they will change production Feishu Bitable contents. This can lead to unintended data corruption or unauthorized modification when an agent or user treats examples as harmless exploratory commands.

Content

No source excerpt is available for this finding.