Back to skill

Security audit

TRMNL Display

Security checks for vulnerabilities and agentic risk

Overview

This TRMNL skill mostly matches its stated purpose, but it can install a mutable global CLI and send generated content to a configured TRMNL webhook without clear pre-send confirmation.

Review this before installing if you use TRMNL with private or sensitive content. Pin or locally install the CLI instead of globally installing `trmnl-cli@latest`, do not use sudo, verify the configured plugin URL, and require an explicit confirmation of the target and content before each send. Avoid displaying secrets, personal data, or confidential summaries unless you intend them to be sent to TRMNL.

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)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:14
Finding

Unpinned Global Installation of a Mutable Third-Party CLI

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:43
Finding

Predictable Shared Temporary File Enables Symlink and Race Attacks

Content
View full analysis
/tmp/trmnl-content.html << 'EOF'
Hello TRMNL!
My Plugin
EOF # Send to display trmnl send --file /tmp/trmnl-content.html ``` ### Technical Analysis The workflow uses a fixed filename in the system-wide `/tmp` directory. The shell redirection does not securely create a new file and does not verify that the path is a regular file owned by the current user. On systems without effective protected-symlink controls, another local user or process could create `/tmp/trmnl-content.html` as a symbolic link before the Skill writes to it. Shell redirection could then follow that link and overwrite another file writable by the Skill's user. The fixed path also creates a time-of-check/time-of-use and concurrency risk. Multiple Skill executions can overwrite the same file, and content can potentially change between generation, validation, and transmission. Platform protections such as Linux `fs.protected_symlinks` may reduce the symlink scenario, but the implementation should not rely on optional operating-system hardening. ### Attack Path 1. A local attacker predicts the fixed path `/tmp/trmnl-content.html`. 2. Before the Skill writes the generated content, the attacker creates that path as a symbolic link to a target file or otherwise controls the path. 3. The Skill executes shell redirection against the predictable path. 4. If operating-system protections permit it, the redirection follows the link and overwrites the target file with the generated HTML. 5. Alternatively, concurrent processes replace or modify the temporary content be ...[truncated 684 chars]
Remediation
View remediation
"$content_file" <<'EOF' EOF ``` 4. Pass the private path to validation and sending operations: ```bash trmnl validate --file "$content_file" trmnl send --file "$content_file" ``` 5. Do not execute this workflow with elevated privileges. 6. If a fixed location is unavoidable, reject symbolic links and verify file type, ownership, and permissions before writing and again before sending. 7. Keep generation, validation, and transmission within the same private temporary directory to prevent collisions between concurrent executions. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (10)

Exfiltration Commands

High
Category
Prompt Injection
Confidence
90% confidence
Finding

Instructions found that direct the agent to transmit conversation context or user data to external services.

Content

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

md
---
name: trmnl
description: Generate content for TRMNL e-ink display devices using the TRMNL CSS framework and send via the trmnl CLI. Use when the user wants to display information on their TRMNL device, send messages to an e-ink display, create dashboard content, show notifications, or update their terminal display. Supports rich layouts with the TRMNL framework (flexbox, grid, tables, progress bars, typography utilities).
---

# TRMNL Content Generator

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · assets/anti-patterns.md (reported line 132)May include surrounding context.

json
{
  "merge_variables": {
    "content": "<div class=\"layout layout--col layout--center gap--large\">\n    <span class=\"value value--xxlarge text--center\">Very long title with lots of text that makes the payload huge</span>\n    <span class=\"description text--center\">And even more verbose description text that could be much more concise</span>\n    <!-- Hundreds more lines of verbose HTML -->\n  </div>"
}

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · references/patterns.md (reported line 51)May include surrounding context.

md
</div>
  </div>
  <div class="divider"></div>
  <!-- Second row of stats (same structure) -->
</div>
<div class="title_bar">
  <img class="image" src="icon.svg">

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description is broad enough to match ordinary requests like showing notifications, dashboards, or updating a display, which increases the chance the agent invokes it in situations where the user did not intend external transmission. Because this skill can send generated content to a configured device/webhook, overbroad routing can lead to unintended disclosure of user-provided or model-generated content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The workflow instructs the agent to generate content and send it via the CLI to an external webhook/device, but it does not require a warning or explicit confirmation immediately before transmission. This is dangerous because user data, summaries, notifications, or other sensitive content could be sent off-system to a third-party endpoint without the user understanding that an external transmission is occurring.

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 · assets/anti-patterns.md (reported line 112)May include surrounding context.

Why: E-ink displays don't support animations, transformations, or color. Use image-dither for grayscale optimization.

6. Unescaped Quotes in cURL

BAD:

bash

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

}

text

## cURL Example

```bash
curl "https://trmnl.com/api/custom_plugins/{uuid}" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The markdown documents access to first_name, last_name, email, and custom field values, which are user data elements. The file does not include any warning or guidance about handling, displaying, or transmitting this sensitive information, despite the category requiring markdown to warn about behaviors affecting user privacy.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation explicitly states that HTML is not auto-escaped by default and encourages placing full HTML into merge variables, but it does not warn about sanitizing untrusted input. In a skill whose purpose is generating display content and sending it via webhook/CLI, this increases the chance that user-controlled or external data will be injected into rendered markup, risking content spoofing, data leakage, or downstream rendering issues depending on the consumer.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

Lines L047-L050 describe locale support using only en-US, de-DE, and fr-FR, which can imply a fixed set of preferred locales rather than user-selectable formatting. This may conflict with language/locale policy expectations because the text does not state that users can choose other locales or that these are merely examples.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.