Back to skill

Security audit

Postiz Extended

Security checks for vulnerabilities and agentic risk

Overview

This social-posting skill is purpose-aligned overall, but it ships real-looking Postiz login credentials and stores reusable session cookies insecurely.

Review before installing. Do not use the embedded Postiz account credentials; the publisher should rotate that password, revoke sessions, remove secrets from the skill and history, require user-supplied credentials or tokens, store cookies only in a private protected location or memory, and add explicit confirmation for immediate publish and delete actions.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/post.py:36
Finding

Hardcoded Postiz Account Credentials

Content
View full analysis

Vulnerability Details

File Location: scripts/post.py:36-41, scripts/check_duplicates.py:22-28, and SKILL.md:49-54
Vulnerability Type: Hardcoded plaintext credentials
Risk Level: High

Vulnerable Code

scripts/post.py:36-41:

python
CREDENTIALS = {
    "email": "sascha@mykuhlmann.com",
    "password": "Postiz2026!",
    "provider": "LOCAL"
}

scripts/check_duplicates.py:22-28:

python
POSTIZ_URL = "https://postiz.home.mykuhlmann.com"
COOKIE_FILE = "/tmp/postiz-cookies.txt"
CREDENTIALS = {
    "email": "sascha@mykuhlmann.com",
    "password": "Postiz2026!",
    "provider": "LOCAL"
}

SKILL.md:49-54:

bash
# Login and save cookie (required before any API call)
curl -s -c /tmp/postiz-cookies.txt \
  'https://postiz.home.mykuhlmann.com/api/auth/login' \
  -H 'Content-Type: application/json' \
  -d '{"email":"sascha@mykuhlmann.com","password":"Postiz2026!","provider":"LOCAL"}'

Technical Analysis

A Postiz account email address and password are embedded directly in executable source files and published in the Skill documentation. Secrets stored this way become available to anyone who can download, inspect, clone, archive, or otherwise access the project.

Both scripts automatically submit these credentials to the Postiz authentication endpoint when an existing session receives an HTTP 401 response. The authenticated session is subsequently used to list integrations, retrieve posts, upload media, and create social-media posts. Therefore, disclosure is not limited to an inactive configuration value; the credential is directly connected to privileged application functionality.

Attack Path

  1. An attacker obtains a copy of the Skill or reads its source code.
  2. The attacker extracts the plaintext email address and password.
  3. The attacker submits the credentials to https://postiz.home.mykuhlmann.com/api/auth/login.
  4. The server retur ...[truncated 1060 chars]
Remediation
View remediation

Remediation Suggestions

  1. Immediately rotate the exposed Postiz password and revoke all active sessions created with the old credential.

  2. Review Postiz audit records for unauthorized logins, uploads, drafts, scheduled posts, or publications.

  3. Remove the credential from all scripts, documentation, repository history, release archives, and distributed Skill packages.

  4. Read authentication material from protected environment variables or an operating-system credential store instead:

    python
    import os
    
    email = os.environ["POSTIZ_EMAIL"]
    password = os.environ["POSTIZ_PASSWORD"]
    credentials = {
        "email": email,
        "password": password,
        "provider": "LOCAL",
    }
    
  5. Fail closed with a clear error when required secret values are absent; do not include fallback passwords.

  6. Prefer a dedicated, revocable, least-privilege API token over a reusable account password if Postiz supports token authentication.

  7. Use a dedicated automation account whose permissions and connected integrations are limited to the required posting workflow.

  8. Add automated secret scanning to version-control and release pipelines.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/post.py:67
Finding

Authentication Cookies Stored in a Predictable Shared Temporary File

Content
View full analysis

Vulnerability Details

File Location: scripts/post.py:35,67-85, scripts/check_duplicates.py:21,32-59, and SKILL.md:49-51
Vulnerability Type: Unsafe temporary-file handling and insecure session storage
Risk Level: High

Vulnerable Code

scripts/post.py:35 defines a fixed location in a shared temporary directory:

python
COOKIE_FILE = "/tmp/postiz-cookies.txt"

scripts/post.py:67-85 reads and writes reusable session cookies without enforcing ownership, restrictive permissions, exclusive creation, or symlink protection:

python
def _load_cookies(self):
    """Load cookies from file if they exist."""
    cookie_path = Path(COOKIE_FILE)
    if cookie_path.exists():
        # Parse Netscape cookie file format
        with open(cookie_path) as f:
            for line in f:
                if line.startswith('#') or not line.strip():
                    continue
                parts = line.strip().split('\t')
                if len(parts) >= 7:
                    self.session.cookies.set(parts[5], parts[6], domain=parts[0])

def _save_cookies(self):
    """Save cookies to file in Netscape format."""
    with open(COOKIE_FILE, 'w') as f:
        f.write("# Netscape HTTP Cookie File\n")
        for cookie in self.session.cookies:
            f.write(f"{cookie.domain}\tTRUE\t{cookie.path}\t"
                   f"{'TRUE' if cookie.secure else 'FALSE'}\t"
                   f"{cookie.expires or 0}\t{cookie.name}\t{cookie.value}\n")

scripts/check_duplicates.py:32-59 implements the same unsafe storage pattern:

python
def get_session():
    """Get authenticated session."""
    session = requests.Session()
    
    # Try to load existing cookies
    try:
        with open(COOKIE_FILE) as f:
            for line in f:
                if line.startswith('#') or not line.strip():
                    continue
                parts = line.strip(
...[truncated 3699 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer keeping session cookies in memory and avoid persisting them unless persistence is operationally necessary.
  2. If persistence is required, store session data in a per-user private state directory rather than /tmp, such as a directory under the platform-specific user configuration or state location.
  3. Create the parent directory with mode 0700 and the cookie file with mode 0600.
  4. Use atomic and exclusive file-creation operations, reject symbolic links, and verify that any existing file is a regular file owned by the current effective user.
  5. Avoid sharing one cookie file between users or unrelated script executions.
  6. Delete expired session data and revoke server-side sessions after suspected local disclosure.
  7. Ensure cookies are only transmitted over HTTPS and preserve the server-provided cookie attributes when serializing them.
  8. Consider using a secure credential store or keyring if persistent session material must be retained.

T08 · Insecure Dependencies

Warning
Location
scripts/post.py:28
Finding

Unpinned Runtime Dependency Resolution

Content
View full analysis

Vulnerability Details

File Location: scripts/post.py:28-33 and scripts/check_duplicates.py:15-20
Vulnerability Type: Unpinned third-party dependency
Risk Level: Medium

Vulnerable Code

scripts/post.py:28-33:

python
# /// script
# requires-python = ">=3.10"
# dependencies = ["requests"]
# ///

import requests

scripts/check_duplicates.py:15-20:

python
# /// script
# requires-python = ">=3.10"
# dependencies = ["requests"]
# ///

import requests

The documented execution workflow uses uv run, allowing the inline dependency declaration to be resolved at runtime without an exact version or integrity hash.

Technical Analysis

Both scripts declare requests without a version constraint, lockfile, or package hash. Consequently, runtime dependency resolution can select a package release that differs from the version originally reviewed and tested.

The package name itself is not a demonstrated typosquat, and the audit found no evidence that the current requests package is malicious. The vulnerability is the mutable and unauthenticated-by-project dependency selection process: a future compromised release, package-index compromise, malicious configured mirror, or unexpected incompatible update could alter the code executed by the Skill without any modification to the audited project.

Because the dependency is imported by scripts that handle account credentials, authentication cookies, post content, and uploaded files, compromise of the dependency would place those assets within reach of dependency code.

Attack Path

  1. A user invokes one of the documented uv run commands.
  2. The resolver processes the unpinned requests dependency.
  3. It obtains the currently selected release from the user's configured package index or mirror.
  4. If that source or selected release has been compromised, malicious dependency code is installed or loaded.
  5. The dep ...[truncated 897 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin requests to a reviewed exact version rather than using an unconstrained package name.
  2. Generate and commit a lockfile that records all transitive dependency versions.
  3. Require package integrity hashes where supported by the installation workflow.
  4. Restrict dependency downloads to approved HTTPS package indexes or an internally controlled package mirror.
  5. Review dependency changes before updating the lockfile and run automated vulnerability scanning against direct and transitive dependencies.
  6. Use isolated environments for script execution and avoid running the scripts with elevated operating-system privileges.
  7. Establish a controlled update process so dependency versions change intentionally rather than implicitly at runtime.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A second material mismatch exists between the broad feature claims and the actual documented behavior, which centers on a narrow set of example API calls against a fixed personal instance. Overstating capabilities while omitting concrete sensitive behaviors makes risk assessment harder and can cause unsafe automation decisions, especially around posting, deletion, and account access.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A second material mismatch exists between the broad feature claims and the actual documented behavior, which centers on a narrow set of example API calls against a fixed personal instance. Overstating capabilities while omitting concrete sensitive behaviors makes risk assessment harder and can cause unsafe automation decisions, especially around posting, deletion, and account access.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The documentation contains concrete login credentials for a real Postiz instance. Anyone who can read the skill may be able to authenticate to that service, access connected social accounts, schedule or publish content, delete posts, or pivot into broader compromise depending on what the Postiz account can reach.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The authentication example normalizes insecure secret handling by embedding plaintext credentials directly in the command with no safeguards. This encourages leakage through version control, logs, shell history, screenshots, and downstream copies of the skill, making unauthorized reuse highly likely.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script hardcodes production-style login credentials and automatically uses them to authenticate against a live Postiz instance. Anyone with access to the skill can recover the credentials and obtain authenticated access, and the same code path also persists reusable session state, increasing the blast radius beyond a simple local helper.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script stores authenticated cookies in /tmp/postiz-cookies.txt, a predictable shared filesystem location that other local users or processes may read, copy, or reuse. Because the cookie grants authenticated API access, theft of that file can enable account takeover or unauthorized post management without knowing the password.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Hardcoded credentials in distributed code are secrets exposure by design: any reader, downstream consumer, or log/archive of the repository can extract and use them. In this skill's context, the credentials provide direct access to a social-posting system, which could allow unauthorized viewing, scheduling, modification, or deletion of posts across connected channels.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documents shell commands, network access, cookie storage, and file interactions but does not declare any explicit tool scope or permissions boundaries. In an agent setting, this increases the chance of the skill being invoked with broader capabilities than users expect, enabling outbound requests and local state changes without clear disclosure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

This command transmits authentication credentials to an external host and stores the resulting session cookie locally. Because the endpoint is a specific self-hosted instance and the credentials are embedded, use of this command can grant unauthorized remote account access and enable abuse of connected social media integrations.

Content

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

bash
# Login and save cookie (required before any API call)
curl -s -c /tmp/postiz-cookies.txt \
  'https://postiz.home.mykuhlmann.com/api/auth/login' \
  -H 'Content-Type: application/json' \
  -d '{"email":"sascha@mykuhlmann.com","password":"Postiz2026!","provider":"LOCAL"}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill includes immediate publishing and delete operations without emphasizing that these actions are irreversible or account-affecting. In an agent workflow, that omission can lead to accidental post publication or deletion of scheduled content, causing reputational and operational harm.

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

Upload Image

bash
# Upload returns {id, path}
curl -s -b /tmp/postiz-cookies.txt \
  'https://postiz.home.mykuhlmann.com/api/media/upload-simple' \
  -F 'file=@/path/to/image.png'

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 · SKILL.md (reported line 184)May include surrounding context.

Twitter/X Threads

For longer content on X, create a thread:

json
"value": [

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script silently writes authenticated session cookies to disk without clear user notice or consent, creating hidden credential material on the host. Even if intended for convenience, undisclosed persistence of auth state increases the chance of accidental exposure, reuse by other tools, and long-lived compromise if the file is left behind.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring describes posting to only three platforms, and the code implements content validation, media upload, listing posts, and creating posts/drafts/now posts for those same three platforms. It does not implement thread creation, deduplication checks before posting, update/delete management, next-slot lookup, or support for the many additional channels claimed in the manifest, creating a clear description-to-behavior mismatch for this skill file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script stores authentication cookies in /tmp, a shared and commonly accessible location on multi-user systems. If file permissions are weak or another local process/user can read or replace the file, session tokens could be stolen or tampered with, enabling unauthorized access to the Postiz account.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Persisting authentication cookies to disk without clear disclosure increases the chance that sensitive session material is retained longer than users expect. If the host is compromised, backed up insecurely, or shared with other users, those cookies can be reused to impersonate the account without needing the password.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

When --now is used, the script proceeds to create and publish posts immediately to external platforms. Although it prints that it is creating a post, there is no confirmation step before the irreversible network action of publishing user content.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The module docstring frames the script as a poster with validation, emphasizing posting workflows in its examples. However, the implemented CLI also supports draft creation and listing existing posts, so the inline documentation presents a narrower intent than what the code actually does.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.