Back to skill

Security audit

TARDIS

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a time tracker, but it also includes under-scoped email, webhook, credential-loading, and public tunnel behavior that users should review carefully before installing.

Install only if you intend to use TARDIS's networked email/webhook features and can run them in a constrained account. Avoid running the webhook server or tunnel helper on sensitive hosts, do not keep unrelated secrets in generic .env files accessible to the skill, require signed SendGrid webhooks with cryptography installed, and treat ACTION milestones as unsafe unless you add explicit approval and allowlist controls.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/sendgrid_webhook.py:123
Finding

Webhook authentication is optional and fails open when cryptographic verification is unavailable

Content
View full analysis
bool: """Verify SendGrid webhook signature using ECDSA.""" if not CRYPTO_AVAILABLE: log("Cryptography library not available - skipping signature verification", "WARN") return True ``` ```python # Signature verification public_key = get_webhook_public_key() if public_key: signature = self.headers.get("X-Twilio-Email-Event-Webhook-Signature", "").strip() timestamp = self.headers.get("X-Twilio-Email-Event-Webhook-Timestamp", "").strip() if not signature or not timestamp: log("Webhook denied: missing signature headers", "WARN") self.send_response(403) self.send_header("Content-Type", "application/json") self.end_headers() self.wfile.write(json.dumps({"status": "denied", "reason": "missing_signature"}).encode()) return if not validate_timestamp(timestamp): log("Webhook denied: timestamp invalid", "WARN") self.send_response(403) self.send_header("Content-Type", "application/json") self.end_headers() self.wfile.write(json.dumps({"status": "denied", "reason": "timestamp_invalid"}).encode()) return if not verify_signature(raw_body, signature, timestamp, public_key): log("Webhook denied: signature invalid", "WARN") self.send_response(403) self.send_header("Content-Type", "application/json") self.end_headers() self.wfile.write(json.dumps({"status": "denied", "reason": "signature_invalid"}).encode()) return log("Webhook signature verified ✓") else: log("Webhook received (no signature verification configured)", "WARN") ``` ### Tec ...[truncated 2329 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sendgrid_webhook.py:326
Finding

Unbounded webhook request body permits remote memory and service exhaustion

Content
View full analysis
Remediation
View remediation
MAX_BODY_SIZE: self.send_error(413, "Payload Too Large") return ``` 3. Configure socket read timeouts to reduce slow-request denial-of-service risk. 4. Deploy behind a production reverse proxy that enforces body-size, connection, concurrency, and rate limits. 5. Consider a production-grade HTTP server rather than the single-threaded development server. 6. Limit the number of events accepted in one JSON batch and validate field lengths before persistence or forwarding. 7. Add tests for oversized, malformed, negative, and slowly delivered request bodies. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/meter.py:28
Finding

Automatic loading of broad environment files exposes unrelated credentials to the process

Content
View full analysis
Remediation
View remediation

other

Warning
Location
scripts/sendgrid_webhook.py:277
Finding

Complete SendGrid event payloads containing personal data are retained indefinitely

Content
View full analysis
None: """Write event to a JSON log file for persistence.""" events_file = os.path.expanduser("~/.openclaw/sendgrid-events.jsonl") try: Path(events_file).parent.mkdir(parents=True, exist_ok=True) with open(events_file, "a") as f: record = { "received_at": int(time.time()), "event": event } f.write(json.dumps(record) + "\n") except Exception as e: log(f"Could not write event to log: {e}", "WARN") ``` ```python # Write to persistent log write_event_to_log(event) # Format and send to Discord message = format_event_message(event) success, result = send_to_discord(message) ``` ### Technical Analysis The webhook server stores the complete event dictionary in `~/.openclaw/sendgrid-events.jsonl`. SendGrid event payloads can contain recipient email addresses, clicked URLs, IP addresses, user-agent data, delivery failure details, custom arguments, and provider identifiers. Only a limited subset of these fields is required to generate the declared Discord notification. Persisting the complete payload therefore exceeds the minimum data required for notification functionality. The file is append-only at the application level and has no rotation, expiration, size limit, redaction, or documented retention period. File creation also relies on the process umask rather than explicitly enforcing restrictive permissions. The separate processed-ID file does not remove or sanitize processed events. When unsigned webhooks are accepted, an unauthenticated attacker can also append arbitrary event objects to this file, amplifying disk-consumption and log-injection concerns. ### Attack Path 1. SendGrid su ...[truncated 1330 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (50)

Tainted flow: 'req' from os.environ.get (line 673, credential/environment) → urllib.request.urlopen (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/meter.py (reported line 476)May include surrounding context.

python
)
    
    try:
        with urllib.request.urlopen(req) as response:
            return True, f"Email sent to {to_email}"
    except urllib.error.HTTPError as e:
        error_body = e.read().decode('utf-8') if e.fp else str(e)

Tainted flow: 'req' from os.environ.get (line 673, credential/environment) → urllib.request.urlopen (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/meter.py (reported line 684)May include surrounding context.

python
)
    
    try:
        with urllib.request.urlopen(req) as response:
            return True, f"Email sent to {to_email}"
    except urllib.error.HTTPError as e:
        error_body = e.read().decode('utf-8') if e.fp else str(e)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README documents capabilities well beyond a simple hour-meter: outbound email, public webhook intake, forwarding to Discord/OpenClaw, and notification/action flows. These features expand the trust boundary and create opportunities for data exfiltration, untrusted event ingestion, and unintended side effects that are not justified by the core time-tracking purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Allowing milestone messages to be interpreted as ACTION: instructions turns user-modifiable meter content into agent-executable commands. If meters.json or related configuration is altered by another process or attacker, the skill can become a command injection path for arbitrary agent actions unrelated to time tracking.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Running an HTTP server, receiving SendGrid webhooks, verifying signatures, posting to Discord, and storing event logs materially changes the risk profile from local tracking to internet-facing event processing. If users rely on the benign description, they may enable or deploy a component that accepts external input and handles potentially sensitive engagement data without appropriate review.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Running an HTTP server, receiving SendGrid webhooks, verifying signatures, posting to Discord, and storing event logs materially changes the risk profile from local tracking to internet-facing event processing. If users rely on the benign description, they may enable or deploy a component that accepts external input and handles potentially sensitive engagement data without appropriate review.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Running an HTTP server, receiving SendGrid webhooks, verifying signatures, posting to Discord, and storing event logs materially changes the risk profile from local tracking to internet-facing event processing. If users rely on the benign description, they may enable or deploy a component that accepts external input and handles potentially sensitive engagement data without appropriate review.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This script manages a SendGrid webhook listener and a Cloudflare tunnel, capabilities that are unrelated to a time-tracking/hour-meter skill. The mismatch in stated purpose versus implemented behavior is a strong indicator of hidden functionality and materially increases the risk that the skill is being used to establish unauthorized network services or persistence.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Referencing /root/.env indicates access to a privileged secret store, and in this context the skill loads and exports its contents. This creates unnecessary credential exposure and increases the blast radius if the script or spawned child processes are compromised.

Content

Scanner excerpt · scripts/check-webhook-services.sh (reported line 5)May include surrounding context.

sh
# Check and restart SendGrid webhook services if down
# Only outputs when a restart happens

# Source .env for Discord webhook URL
if [ -f /root/.env ]; then
    export $(grep -v '^#' /root/.env | xargs)
fi

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The command export $(grep -v '^#' /root/.env | xargs) indiscriminately loads variables from a root-owned environment file, which is an unsafe pattern for handling credentials. It can expose secrets to subprocesses, mis-parse values containing spaces or special characters, and accidentally import unrelated sensitive settings.

Content

Scanner excerpt · scripts/check-webhook-services.sh (reported line 6)May include surrounding context.

sh
# Only outputs when a restart happens

# Source .env for Discord webhook URL
if [ -f /root/.env ]; then
    export $(grep -v '^#' /root/.env | xargs)
fi

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Although this line itself is not the secret access, it is part of the .env loading block that conditions privileged secret ingestion for the script. In the context of this file, it contributes to unnecessary secret handling in a skill whose declared purpose does not justify credential access.

Content

Scanner excerpt · scripts/check-webhook-services.sh (reported line 7)May include surrounding context.

sh
# Source .env for Discord webhook URL
if [ -f /root/.env ]; then
    export $(grep -v '^#' /root/.env | xargs)
fi

WEBHOOK_PORT=8089

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Starting cloudflared tunnel exposes a local service to the public internet via a transient external URL, creating inbound access that is unjustified for the declared skill purpose. This can bypass normal network exposure controls and provide covert remote access to a locally hosted webhook service.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The code explicitly implements automatic credential access by loading .env content for SENDGRID_API_KEY during module initialization. In a utility whose core purpose is local time tracking, unsolicited secret discovery is high-risk because it broadens access to credentials without a tightly scoped trigger or clear consent.

Content

Scanner excerpt · scripts/meter.py (reported line 28)May include surrounding context.

python
# Default storage location
DEFAULT_STORAGE = os.path.expanduser("~/.openclaw/meters.json")

# Auto-load .env file if SENDGRID_API_KEY not in environment
def _load_dotenv():
    """Load .env file if SENDGRID_API_KEY not already set."""
    if os.environ.get("SENDGRID_API_KEY"):

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script automatically reads .env files, including /root/.env, and uses the recovered credential to enable outbound email through SendGrid. For a time-tracking utility, implicit credential discovery materially increases privilege and secrecy risks because the tool can consume sensitive local secrets without an explicit user action tied to credential access.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The documented behavior confirms the tool will source SENDGRID_API_KEY automatically, which constitutes credential access beyond the minimum needed for basic meter operations. This elevates risk because secret handling is enabled by default rather than only when email functionality is explicitly invoked.

Content

Scanner excerpt · scripts/meter.py (reported line 30)May include surrounding context.

python
# Auto-load .env file if SENDGRID_API_KEY not in environment
def _load_dotenv():
    """Load .env file if SENDGRID_API_KEY not already set."""
    if os.environ.get("SENDGRID_API_KEY"):
        return
    env_paths = [

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

Reading ~/.env automatically is a credential-access behavior that may ingest secrets unrelated to this tool. Because .env files commonly contain API keys and tokens, this expands the script's access to local secrets in a way disproportionate to its stated purpose.

Content

Scanner excerpt · scripts/meter.py (reported line 34)May include surrounding context.

python
if os.environ.get("SENDGRID_API_KEY"):
        return
    env_paths = [
        os.path.expanduser("~/.env"),
        os.path.expanduser("/root/.env"),
        ".env"
    ]

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

Attempting to read /root/.env is especially dangerous because it targets a privileged location that may contain highly sensitive secrets. In the context of a personal meter utility, probing root-owned secret material is unjustified and significantly raises suspicion and impact.

Content

Scanner excerpt · scripts/meter.py (reported line 35)May include surrounding context.

python
return
    env_paths = [
        os.path.expanduser("~/.env"),
        os.path.expanduser("/root/.env"),
        ".env"
    ]
    for env_path in env_paths:

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

Automatically reading a local .env in the current working directory can unintentionally consume secrets from unrelated projects. While less severe than /root/.env, it still creates surprising credential access and couples a simple timer tool to ambient secrets in the execution environment.

Content

Scanner excerpt · scripts/meter.py (reported line 36)May include surrounding context.

python
env_paths = [
        os.path.expanduser("~/.env"),
        os.path.expanduser("/root/.env"),
        ".env"
    ]
    for env_path in env_paths:
        if os.path.exists(env_path):

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This file implements a SendGrid webhook receiver and Discord notification bridge, which is materially unrelated to the stated hour-meter purpose of tracking elapsed time with tamper-evident locking. That mismatch is dangerous because it adds unexpected network ingress/egress and data-handling behavior to a skill users would not reasonably expect to expose an HTTP service or relay email telemetry.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code starts an HTTP server and can transmit received content to Discord or a gateway, creating both an externally reachable attack surface and an outbound data exfiltration channel. In the context of an hour-meter skill, these capabilities are unjustified and increase risk because operators may deploy it without realizing they are exposing a webhook endpoint and forwarding event contents off-host.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The marketplace blurb advertises features not reflected in the described core operations, including count-down/count-between modes, milestone notifications via Discord/Telegram/OpenClaw channels, and a career projection calculator. Security-wise, overstating capabilities can mislead users into granting trust, integrating the skill into workflows it may not safely support, or assuming external communication features exist and are vetted when they may be absent, incomplete, or implemented elsewhere without proper review.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 69)May include surrounding context.

md
🔒 LOCKED: smoke-free

╔══════════════════════════════════════════════════════════════╗
║  PAPER CODE (write this down):                               ║
║                                                              ║
║     A7F3-B92C-1D4E-8F6A-7                                    ║
║                                                              ║

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 119)May include surrounding context.

📋 Human-Friendly Paper Codes

Forget copying 64-character hex strings. Get a short, checksummed code you can actually write on paper:

text
PAPER CODE: A7F3-B92C-1D4E-8F6A-7

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documents capabilities that imply environment access, filesystem writes, shell execution, and network use, but it does not declare any tool scope or permissions boundaries. In an agent environment this weakens least-privilege controls and makes it harder for users or platforms to understand and restrict what the skill may do.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation frames the skill as local hour-meter tracking, yet later sections add email delivery, webhook serving, and Discord notifications. This creates a security disclosure gap that can mislead operators about data flows, external communications, and attack surface.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.