Back to skill

Security audit

Medium Blog Post Creator

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly purpose-aligned, but it can publicly create and update GitHub repositories and expose Medium draft links with insufficient safeguards.

Install only if you are comfortable with the agent using your authenticated GitHub and Medium sessions, creating or updating a public GitHub repository, and publishing draft source pages publicly. Confirm the target owner, repo, branch, and public URL before each run, avoid sensitive content, and do not commit Medium draft editor URLs to a public repo.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:299
Finding

Command and JSON Injection Through Unvalidated Workflow Placeholders

Content
View full analysis
" if [ ! -d "" ]; then gh repo clone / "" else cd "" && git pull --rebase origin fi ``` ```bash gh repo create / \ --public \ --description "Static blog for Medium cross-posting" \ --clone \ --add-readme ``` ```bash printf '%s\n' '{' \ ' "schema_version": 1,' \ " \"github_owner\": \"\"," \ " \"github_repo\": \"\"," \ " \"pages_url\": \"\"," \ " \"default_author\": \"\"," \ " \"branch\": \"\"" \ '}' > "/.medium-skill-config.json" ``` ```bash git commit -m "feat(posts): add \"\" []" git push origin ``` ```bash git commit -m "chore(posts): link medium draft for \"\"" git push origin ``` ### Technical Analysis The workflow directs the Agent to substitute user-controlled or configuration-derived values directly into shell source. These values include the post title, GitHub owner, repository name, branch, local path, and values read from persistent configuration files. The post title is embedded inside a double-quoted shell argument. Double quotes prevent ordinary word splitting but do not prevent command substitution. For example, a title containing `$(malicious-command)` would still be evaluated by a POSIX shell when the generated command runs. Repository and branch placeholders are used without shell quoting in multiple commands. Shell metacharacters can therefore alter command structure, while values beginning with a hyphen can potential ...[truncated 2596 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:349
Finding

Public Disclosure of the Medium Draft Editor URL

Content
View full analysis
posts/-/` (include the trailing slash — Medium's importer is sensitive to it). 3. Click Import. 4. Wait for confirmation (text like "Imported the story"). 5. Click "See your story" / "Open draft" to open the draft editor at `https://medium.com/p//edit`. 6. **Do not click Publish.** Leave it as a draft. 7. Copy the draft editor URL. ``` ```text ### Step 9 — Update metadata with the Medium URL 1. Set `medium_url` in `posts/-/meta.json` to the draft URL. 2. Set `medium_url` for the same post in `posts/index.json`. 3. Commit and push: ``` ```bash git add posts/-/meta.json posts/index.json git commit -m "chore(posts): link medium draft for \"\"" git push origin ``` ### Technical Analysis The Skill explicitly creates or uses a public GitHub repository. After importing the public post into Medium, it copies the authenticated draft editor URL and stores that URL in `meta.json` and `posts/index.json`. It then commits and pushes both files to the public repository. Publishing the draft editor URL is not necessary for the declared core operation of importing a page into Medium. A machine-local record would provide end-to-end traceability without exposing the unpublished draft identifier. The URL is not established to be an authentication token, and Medium may independently enforce account authorization. Nevertheless, it identifies an unpublished draft and exposes its editor endpoint and draft identifier to anyone who can read the public repository. This contradicts the assumption that repository metadata contains only information safe for public exposure. ### Attack Path 1. ...[truncated 1312 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (12)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `references/configuration.md`: persistent-config schemas, resolution rules,

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `references/configuration.md`: persistent-config schemas, resolution rules,

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `references/configuration.md`: persistent-config schemas, resolution rules,

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `references/configuration.md`: persistent-config schemas, resolution rules,

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/post-template.html (reported line 14)May include surrounding context.

html
<meta property="article:published_time" content="YYYY-MM-DDTHH:MM:SSZ">
  <meta property="article:author" content="POST_AUTHOR">
  <link rel="canonical" href="POST_CANONICAL_URL">
  <!-- <style> is for local preview only — Medium's URL importer strips it. -->
  <style>
    body {
      font-family: Georgia, 'Times New Roman', serif;

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/post-template.html (reported line 119)May include surrounding context.

html
will convert it into an embed block:
  </p>

  <!-- Replace VIDEO_ID with a real YouTube id, or delete this block. -->
  <p>https://www.youtube.com/watch?v=VIDEO_ID</p>

  <h2>Closing</h2>

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger phrases are broad enough to activate on generic requests like 'write a blog post about X' or 'blog about X', which can cause the skill to take over ordinary writing tasks and steer them into a GitHub Pages plus Medium publishing workflow. In this skill, that matters because activation can lead to creating public repositories, generating public URLs, and driving browser actions, so an accidental invocation has real side effects beyond simple content drafting.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
81% confidence
Finding

Persisting and reusing last_repo 'without asking' enables the skill to make consequential decisions about where content will be created and published without obtaining fresh user confirmation. In this context, that can result in posts being pushed to an unintended GitHub repository and exposed via GitHub Pages, especially if multiple repos, orgs, or users are present on the machine.

Content

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

md
(Source: **Deploy from a branch** → `<branch>` / `/ (root)`), and wait for
     confirmation before continuing.

6. **Save the repo to the per-install config** so future runs reuse it without
   asking: write `last_repo` (`github_owner`, `github_repo`, `pages_url` =
   `<pages-base-url>`, `branch`) into the per-install config file. Schema in
   `references/configuration.md`.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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/configuration.md (reported line 25)May include surrounding context.

It is never committed, never bundled, never published. Holds personal preferences that are stable across posts but not across machines, plus last_repo — the machine-local pointer to which blog repo to reuse, so later runs can locate it without asking (the marker lives inside the repo, so the skill needs this to know where the repo is in the first place):

json

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The reset phrases are broad natural-language commands like 'Forget everything' and 'Start over' mapped directly to destructive deletion of persistent state. In an agent setting, ambiguous phrasing can be triggered unintentionally by normal conversation or prompt injection in surrounding content, causing loss of local config and/or committed repo state without an explicit confirmation step.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file includes an invocation example of simply asking to "Write a blog post about ...", which is a common phrase that could overlap with ordinary content-generation requests rather than clearly signaling this specific Medium/GitHub Pages automation skill. The README does not provide negative examples or tighter trigger constraints here to distinguish when the skill should activate versus when a generic writing skill should handle the request.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The HTML root element sets lang="en", which enforces English as the document language in a reusable template. For a general-purpose skill asset, this is a natural-language locale constraint with no user opt-in or indication that the template is intentionally region-specific.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.