Back to skill

Security audit

Twitter

Security checks for vulnerabilities and agentic risk

Overview

This Twitter/X automation skill has a coherent purpose, but it exposes its API key in normal command output and can send credentials, post content, and media to a custom or plaintext relay.

Review carefully before installing. Use only a trusted HTTPS AIsa relay, avoid custom relay URLs unless you control them, assume searches, post text, media, and action targets leave the local machine, and do not run status/authorize/post commands with a real key until the API-key output exposure is fixed and any exposed keys are rotated.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/twitter_oauth_client.py:47
Finding

Credentials and User Content Can Be Sent to an Arbitrary or Plaintext Relay

Content
View full analysis
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 ``` ```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 def send_json_request( url: str, payload: Dict[str, Any], timeout: int, aisa_api_key: str, ) -> Dict[str, Any]: request = urllib.request.Request( url, data=json.dumps(payload).encode("utf-8"), headers=build_auth_headers( aisa_api_key, {"Content-Type": "application/json", "Accept": "application/json"}, ), method="POST", ) try: with urllib.request.urlopen(request, timeout=timeout) as response: raw = response.read().decode("utf-8") return parse_response_body(raw, response.status, "ok") ``` ```python def post_single_tweet( config: Dict[str, Any], *, content: Optional[str] = None, media_ids: Optional[list[str]] = None, media_files: Optional[list[Dict[str, Any]]] = None, parent_tweet_id: Optional[str] = None, post_type: Optional[str] = None, ) -> Dict[str, Any]: paylo ...[truncated 4243 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/twitter_oauth_client.py:339
Finding

AISA API Key Is Exposed in Standard Command Output

Content
View full analysis
None: config = load_config(args) response = { "ok": True, "relay_base_url": ...[truncated 3101 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/twitter_oauth_client.py:412
Finding

Media Upload Can Read and Transmit Files from Unrestricted Local Paths

Content
View full analysis
list[Dict[str, Any]]: if not paths: return [] media_files: list[Dict[str, Any]] = [] media_kinds: set[str] = set() seen_paths: set[str] = set() for raw_path in paths: resolved_path = os.path.abspath(os.path.expanduser(raw_path)) normalized_path = os.path.normcase(resolved_path) if normalized_path in seen_paths: continue seen_paths.add(normalized_path) if not os.path.exists(resolved_path): raise RelayConfigError(f"Media file does not exist: {raw_path}") if not os.path.isfile(resolved_path): raise RelayConfigError(f"Media path is not a file: {raw_path}") mime_type = mimetypes.guess_type(resolved_path)[0] or "application/octet-stream" media_kind = mime_type.split("/", 1)[0] if media_kind not in {"image", "video"}: raise RelayConfigError( f"Unsupported media type for {raw_path}: {mime_type}. Only image and video files are supported." ) media_kinds.add(media_kind) with open(resolved_path, "rb") as file_handle: content = file_handle.read() media_files.append( { "field_name": "media_files", "filename": os.path.basename(resolved_path), "content_type": mime_type, "content": content, } ) if len(media_kinds) > 1: raise RelayConfigError("Do not mix image and video files in a single post request.") return media_files ``` ### Technical Analysis The documented workflow expects `--media-file` to reference attachments placed in a local workspace. The executable does not enforce that bounda ...[truncated 2104 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (60)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill documentation claims account-affecting write actions and browser OAuth-based user authorization, but the file only documents relay/API-key-based calls and defers behavior to other references. That mismatch can mislead users and orchestrators about what credentials are used and what actions may occur, creating a consent and trust-boundary problem around posting or engagement on a third-party service.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill documentation claims account-affecting write actions and browser OAuth-based user authorization, but the file only documents relay/API-key-based calls and defers behavior to other references. That mismatch can mislead users and orchestrators about what credentials are used and what actions may occur, creating a consent and trust-boundary problem around posting or engagement on a third-party service.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill documentation claims account-affecting write actions and browser OAuth-based user authorization, but the file only documents relay/API-key-based calls and defers behavior to other references. That mismatch can mislead users and orchestrators about what credentials are used and what actions may occur, creating a consent and trust-boundary problem around posting or engagement on a third-party service.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The status command returns the configured aisa_api_key in normal JSON output, which is a direct secret disclosure. Anyone who can invoke this command or read its output may reuse the credential against the relay or related backend services, enabling unauthorized actions on behalf of the skill. In this skill context, the key is not needed to fulfill the Twitter engagement purpose, so exposing it is especially unjustified.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The status path exposes the configured API key without masking or warning, making credential theft trivial through ordinary program output. Because this client performs authenticated relay actions such as like/follow/unfollow, a stolen key could let an attacker abuse the relay, impersonate legitimate operations, or pivot into related service access depending on backend trust in the key.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README advertises account-affecting actions such as publishing posts, liking tweets, and following or unfollowing users, but it does not warn about side effects, consent boundaries, or privacy implications. In an agent skill context, this omission is dangerous because users or downstream integrators may invoke the skill without realizing it can modify a live social-media account and expose account data through OAuth-scoped access.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares network and environment-variable use but does not define an explicit tool scope such as allowed-tools or permissions. In an agent setting, that omission weakens least-privilege controls and can let a broadly invocable skill access secrets or make outbound requests without clear policy boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill advertises social listening, monitoring, and broad Twitter data collection without a clear privacy warning or disclosure that user queries and target identities are sent to a third-party relay. In this context, the omission matters because the skill is explicitly designed for surveillance-style monitoring and may process sensitive organizational or personal interest patterns.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The action workflow notes OAuth prerequisites but does not prominently warn that like, unlike, follow, unfollow, posting, replying, and quoting will modify the user's Twitter/X account state. In an autonomous-agent context, lack of a clear state-change warning increases the risk of unintended account actions and user-consent failures.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The skill is designed to send authenticated requests to an external AIsa relay using a bearer API key, and the optional relay base URL further enables outbound data transfer. This is security-relevant because prompts, target usernames, tweet IDs, search queries, and potentially account-action metadata leave the local trust boundary and are exposed to a third-party service.

Content

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

export AISA_API_KEY="your-key"

Optional: override the default AIsa relay for OAuth, posting, and engagement

export TWITTER_RELAY_BASE_URL="https://api.aisa.one/apis/v1/twitter" export TWITTER_RELAY_TIMEOUT="30"

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This skill enables real account-affecting actions such as liking, unliking, following, and unfollowing on a user's X/Twitter account, but the introductory text does not clearly warn that these are live external actions. In an agent setting, lack of an explicit high-visibility notice increases the risk of users triggering unintended actions or misunderstanding the consequences of a natural-language request.

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/engage_twitter.md (reported line 66)May include surrounding context.

md
When the user asks to like, unlike, follow, or unfollow on X/Twitter:

1. Do not ask the user for tweet IDs, tweet links, or user IDs.
2. If the user specifies a direct account such as `@elonmusk`, call the `--user` based command.
3. If the user asks for the latest tweet, use `like-latest` or `unlike-latest`.
4. If the user first asked to query tweets, keep the returned `tweets[]` structure in agent context.

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/engage_twitter.md (reported line 78)May include surrounding context.

md
When the user asks to like, unlike, follow, or unfollow on X/Twitter:

1. Do not ask the user for tweet IDs, tweet links, or user IDs.
2. If the user specifies a direct account such as `@elonmusk`, call the `--user` based command.
3. If the user asks for the latest tweet, use `like-latest` or `unlike-latest`.
4. If the user first asked to query tweets, keep the returned `tweets[]` structure in agent context.

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 149)May include surrounding context.

md
When the user asks to like, unlike, follow, or unfollow on X/Twitter:

1. Do not ask the user for tweet IDs, tweet links, or user IDs.
2. If the user specifies a direct account such as `@elonmusk`, call the `--user` based command.
3. If the user asks for the latest tweet, use `like-latest` or `unlike-latest`.
4. If the user first asked to query tweets, keep the returned `tweets[]` structure in agent context.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill describes sending local media files and post content to the AIsa relay backend, but it does not prominently warn users that their attachments and text are transmitted to a third-party relay for processing and publishing. This creates a privacy and data-handling risk because users may assume content stays local or goes directly to Twitter/X.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill's agent instructions default all posts to --type quote, which directly contradicts the documented behavior that normal standalone posts should not include quote/reply relationship fields. This can cause unintended inclusion of relationship metadata, broken posting behavior, or accidental leakage of a quoted target URL into user posts when the user only intended a normal post.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file-level documentation claims the client is read-only, but the shared _request helper explicitly supports POST and automatically includes the API key in the JSON body. In an agent skill context, this mismatch can mislead integrators or policy layers into trusting the tool as non-mutating while later code changes or alternate entrypoints could invoke write-capable requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

This code sends command arguments such as usernames, tweet IDs, search queries, and cursors to an external service via urllib.request.urlopen. Although the module docstring mentions read APIs and bearer auth, there is no visible user-facing warning, confirmation, or logging at the point where user-supplied data is transmitted to a remote endpoint.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The CLI advertises only read APIs, but the underlying request primitive remains generic and capable of non-read HTTP methods. That creates a security-boundary confusion issue: reviewers and users may rely on the help text while the codebase preserves latent write functionality that could be exposed by future changes or indirect use.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest claims capabilities including profiles, timelines, mentions, followers, tweet search, trends, lists, communities, Spaces, and publishing posts. In this file, the implemented commands are limited to listing a user's latest tweets, liking/unliking tweets, following/unfollowing users, and showing relay status, so the described scope does not match the actual behavior present here.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Printing the API key in routine output is a sensitive-data exposure issue and can leak into terminal history, logs, orchestration traces, or agent transcripts. Even if access to the tool is somewhat limited, the skill context increases danger because the secret can authorize actions against the configured relay and is unrelated to the user's requested Twitter task.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring and implemented commands show support for authorize, post, and status only, with relay endpoints limited to /auth_twitter and /post_twitter. This is materially narrower than the manifest description, which claims searching/reading profiles, timelines, mentions, followers, tweet search, trends, lists, communities, Spaces, and liking/following actions.

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 108)May include surrounding context.

md
"""
Twitter relay client for AIsa OAuth authorization and tweet publishing.

Defaults to https://api.aisa.one/apis/v1/twitter and can be overridden with
TWITTER_RELAY_BASE_URL and TWITTER_RELAY_TIMEOUT.

Commands:

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 112)May include surrounding context.

md
"""
Twitter relay client for AIsa OAuth authorization and tweet publishing.

Defaults to https://api.aisa.one/apis/v1/twitter and can be overridden with
TWITTER_RELAY_BASE_URL and TWITTER_RELAY_TIMEOUT.

Commands:

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 116)May include surrounding context.

md
"""
Twitter relay client for AIsa OAuth authorization and tweet publishing.

Defaults to https://api.aisa.one/apis/v1/twitter and can be overridden with
TWITTER_RELAY_BASE_URL and TWITTER_RELAY_TIMEOUT.

Commands: