Back to skill

Security audit

AIsa Twitter API (Search + Post)

Security checks for vulnerabilities and agentic risk

Overview

Review recommended: the skill matches its Twitter/X search-and-post purpose, but it unnecessarily exposes the API key and can send credentials and media to an undocumented custom relay URL.

Install only if you are comfortable giving this skill an AIsa API key and allowing it to post to a real X/Twitter account after OAuth. Before use, verify TWITTER_RELAY_BASE_URL is unset or points to the intended trusted HTTPS relay, avoid posting sensitive drafts or media, use a test account where possible, and treat any logs from this skill as potentially containing the API key until the output behavior is fixed.

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/twitter_oauth_client.py:337
Finding

API Key Disclosed Through Standard Output

Content
View full analysis

Vulnerability Details

File Location: scripts/twitter_oauth_client.py:337-366, scripts/twitter_oauth_client.py:470-478, and scripts/twitter_oauth_client.py:538-551
Vulnerability Type: Plaintext secret exposure in application output
Risk Level: High

Vulnerable Code

python
if result.get("ok") is False or result.get("code") != 200:
    return {
        "ok": False,
        "aisa_api_key": config["aisa_api_key"],
        "is_thread": should_thread,
        "total_chunks": len(chunks),
        "failed_at_chunk": index + 1,
        "results": publish_results,
    }

latest_tweet_id = extract_tweet_id(result)
if not latest_tweet_id:
    return {
        "ok": False,
        "aisa_api_key": config["aisa_api_key"],
        "is_thread": should_thread,
        "total_chunks": len(chunks),
        "failed_at_chunk": index + 1,
        "error": "Missing tweet_id in relay response.",
        "results": publish_results,
    }

return {
    "ok": True,
    "aisa_api_key": config["aisa_api_key"],
    "is_thread": should_thread,
    "total_chunks": len(chunks),
    "results": publish_results,
}
python
output = {
    "ok": result.get("code") == 200 and bool(auth_url),
    "aisa_api_key": config["aisa_api_key"],
    "authorization_url": auth_url,
    "raw_response": result,
}
print(json.dumps(output, indent=2, ensure_ascii=False))
python
response = {
    "ok": True,
    "relay_base_url": config["base_url"],
    "aisa_api_key": config["aisa_api_key"],
    "timeout": config["timeout"],
    "supported_commands": ["authorize", "post", "status"],
    "supported_endpoints": ["/twitter/auth_twitter", "/twitter/post_twitter"],
    "media_upload": {
        "field_name": "media_files",
        "transport": "multipart/form-data",
        "supported_media_types": ["image/*", "video/*"],
    },
}
print(json.dumps(response, indent=2, ensu
...[truncated 1903 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove aisa_api_key from every authorization, posting, error, and status response.
  2. Never print authentication secrets to standard output or standard error.
  3. If key identification is operationally necessary, display only a non-sensitive fingerprint or a fixed mask such as ****.
  4. Add a centralized output-sanitization function that recursively removes fields named aisa_api_key, api_key, authorization, token, or similar secret-bearing fields.
  5. Ensure HTTP error bodies and relay responses are sanitized before printing because an upstream service could reflect credentials.
  6. Add regression tests that configure a known test secret, invoke every command and failure path, and assert that the secret does not appear in captured output.
  7. Rotate any API key that may already have appeared in transcripts or logs, and remove historical copies where feasible.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/twitter_oauth_client.py:44
Finding

Arbitrary HTTP Relay Configuration Can Exfiltrate Credentials and User Content

Content
View full analysis

Vulnerability Details

File Location: scripts/twitter_oauth_client.py:44-68, scripts/twitter_oauth_client.py:78-101, scripts/twitter_oauth_client.py:163-178, and scripts/twitter_oauth_client.py:376-406
Vulnerability Type: Unrestricted network destination and cleartext transmission of sensitive data
Risk Level: High

Vulnerable Code

python
def normalize_base_url(base_url: str) -> str:
    value = base_url.strip().rstrip("/")
    if not value:
        raise RelayConfigError("TWITTER_RELAY_BASE_URL is required.")
    parsed = urllib.parse.urlparse(value)
    if parsed.scheme not in {"http", "https"} or not parsed.netloc:
        raise RelayConfigError("TWITTER_RELAY_BASE_URL must be a valid http(s) URL.")
    return value


def load_config(args: argparse.Namespace) -> Dict[str, Any]:
    base_url = normalize_base_url(
        get_env("TWITTER_RELAY_BASE_URL", DEFAULT_BASE_URL)
    )
    aisa_api_key = getattr(args, "aisa_api_key", None) or get_env("AISA_API_KEY")
    timeout = getattr(args, "timeout", None) or int(get_env("TWITTER_RELAY_TIMEOUT", str(DEFAULT_TIMEOUT)))

    if not aisa_api_key:
        raise RelayConfigError("AISA_API_KEY is required.")

    return {
        "base_url": base_url,
        "aisa_api_key": aisa_api_key,
        "timeout": timeout,
    }
python
def build_auth_headers(aisa_api_key: str, extra_headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
    headers = {
        "Authorization": f"Bearer {aisa_api_key}",
        "User-Agent": DEFAULT_CHROME_USER_AGENT,
    }
    if extra_headers:
        headers.update(extra_headers)
    return headers
python
payload: Dict[str, Any] = {
    "aisa_api_key": config["aisa_api_key"],
}
if content:
    payload["content"] = content
if post_type:
    payload["type"] = post_type
if media_ids:
    payload["media_ids"] = media_ids
if parent_tweet_id:
    par
...[truncated 3467 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require https and reject all cleartext HTTP relay URLs.
  2. For the standard Skill, allowlist the exact documented origin, https://api.aisa.one, and expected API path.
  3. Reject URLs containing user information, unexpected ports, fragments, or hostnames that merely end with a trusted-looking suffix.
  4. Normalize and compare the parsed scheme, hostname, and effective port rather than using string-prefix checks.
  5. If custom relays are a legitimate advanced feature, require explicit command-line opt-in and separate relay credentials. Do not send an AIsa credential to a non-AIsa origin.
  6. Display the effective destination before sending sensitive media to a custom relay and require informed confirmation where interactive execution is available.
  7. Send the API key through only one authenticated channel. Remove aisa_api_key from JSON and multipart bodies if the bearer header is sufficient.
  8. Add tests confirming that HTTP URLs, alternate domains, deceptive subdomains, embedded credentials, and unexpected ports are rejected.
  9. Treat relay-provided authorization URLs as untrusted. Validate their scheme and expected authorization hostname before opening them in a browser or returning them as an approval destination.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (50)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Most of the declared read/search functionality is accurately represented: the code provides GET-based access to user info, timelines, mentions, followers/followings, tweet search/details/replies/quotes/retweeters/thread, trends, lists, communities, and Spaces. However, the description also states that it 'Publishes posts after the user completes OAuth in the browser.' This code chunk does not implement post creation, any write endpoint, OAuth handling, or a browser-based auth flow. Although webbrowser is imported, it is unused. Authentication is via an AISA_API_KEY bearer token from environment/constructor, not user OAuth. Therefore the description materially overstates write/auth capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The description says the skill both reads/searches many categories of Twitter/X data and publishes posts after OAuth. The supplied code only supports three commands: authorize, post, and status. It calls only two relay endpoints: /twitter/auth_twitter and /twitter/post_twitter. There are no endpoints, functions, or logic for fetching profiles, timelines, mentions, followers, searches, trends, lists, communities, or Spaces. On the other hand, the posting functionality is real and somewhat broader than described: it can upload local image/video files, attach media IDs, split oversized text into multi-post threads, and create quote/reply chains. Therefore the declared description materially overstates read/search capabilities and does not accurately represent the actual code's primary behavior, which is OAuth setup plus posting through a relay.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The agent instructions say to default to --type quote for publishing, which directly contradicts earlier guidance that normal standalone posts should not send relationship fields and that quote mode requires a target tweet URL. This can cause unintended quote-post behavior, malformed requests, or accidental disclosure by appending/relating content to another tweet without clear user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README advertises commands that publish posts to Twitter/X but does not clearly warn that these actions affect a real public account and may be difficult or impossible to fully undo once posted. In an agent skill context, this increases the risk of accidental posting, reputational harm, and unintended disclosure because users or downstream agents may treat the examples as routine automation rather than high-impact public actions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares environment and network capabilities via metadata and documented curl/python usage, but it does not explicitly constrain tool scope with permissions or allowed-tools. In an agent environment, this can cause overbroad invocation and make it easier for the skill to access secrets or make outbound requests beyond what reviewers expect.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest advertises posting capability, but the visible file only documents read/search operations and defers publishing to another file. This separation can mislead users and reviewers about what actions the skill may ultimately perform, increasing the chance of unintended account-impacting behavior when the linked posting workflow is invoked.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Broad trigger phrases like 'use when the user asks about Twitter/X data' can cause the skill to activate on ordinary requests without clear user intent to contact a third-party service. In agent systems, overbroad routing increases the risk of unnecessary external transmission of user queries and unintended use of API-backed capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill advertises posting on the user's behalf after OAuth but omits warnings about privacy, reputational risk, and irreversible account actions. In context, this is more dangerous because the skill bridges from passive data access to active social-media publishing, which can materially affect the user's public account.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill documentation only describes OAuth-based posting, while the manifest advertises much broader read/search capabilities. This mismatch can cause the agent or user to assume capabilities and data flows that are undocumented, reducing informed consent and making it harder to evaluate privacy and security boundaries.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The example invocations use generic phrases like "Help me post this to Twitter" and "Post this image to X" without narrowing the activation context or providing exclusions. In a markdown skill description, these broad natural-language triggers could match ordinary user requests and cause unintended invocation because no negative examples or explicit scope constraints are given.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill does not prominently warn that tweet text and attached local media are transmitted to an external platform/backend for publication. In a posting skill, missing disclosure increases the risk of users unintentionally sending sensitive content or workspace files off-platform.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/post_twitter.md (reported line 147)May include surrounding context.

md
## Guardrails

- Do not ask the user for their Twitter password.
- Do not use cookie-based login or proxy-based login unless the user explicitly asks for legacy behavior.
- Do not claim authorization succeeded just because an authorization URL was generated.
- Do not ask for a tweet link or tweet ID just because the user requested `reply`; use `--type reply` directly.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest describes a combined search-and-post Twitter skill, including publishing after browser OAuth. In this file, the module docstring, CLI description, and implemented commands are exclusively read-oriented, and there is no method or command for composing, authorizing, or publishing posts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script retrieves a credential from the environment and uses it for outbound authentication, but gives no user-visible indication that a secret is being used or that it will be sent to an external service. In agent environments, hidden credential use can violate least surprise and complicate trust boundaries, especially when users may assume local-only processing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The client forwards user-supplied queries, usernames, tweet IDs, and similar data to a third-party service at api.aisa.one without any built-in disclosure or consent mechanism. In an agent setting, this can cause unanticipated exfiltration of user interests, targets, or investigation context to an external provider, which is especially sensitive for social listening or investigative use cases.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 56)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 64)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 68)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 72)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 76)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 80)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 84)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 88)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 92)May include surrounding context.

md
DEFAULT_TIMEOUT = 30
DEFAULT_BASE_URL = "https://api.aisa.one/apis/v1"
DEFAULT_CHROME_USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "

Static analysis

No suspicious patterns detected.