Back to skill

Security audit

Markdown Linter

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Markdown linter with an optional external-link checker that should be used cautiously because it makes outbound requests to links found in files.

This skill is reasonable to install for local Markdown linting. Leave --check-external-links disabled for untrusted Markdown or when running inside sensitive corporate/cloud networks unless the tool is sandboxed or updated to block localhost, private IP ranges, metadata endpoints, unsafe redirects, and excessive URL checks.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:271
Finding
Server-Side Request Forgery Through Unrestricted External Link Validation## Vulnerability Details **File Location**: `scripts/main.py`, lines 271–277 **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: Medium ### Vulnerable Code ```python url_pattern = r'\[.*?\]\((https?://[^\s)]+)\)' for i, line in enumerate(lines): for match in re.finditer(url_pattern, line): url = match.group(1) col = match.start(1) try: response = requests.head(url, timeout=5, allow_redirects=True) ``` ### Technical Analysis When external link checking is enabled, the linter extracts HTTP and HTTPS URLs directly from the contents of a Markdown file and sends a `HEAD` request to each URL. The destination is not checked against an allowlist, nor are resolved addresses rejected when they belong to loopback, private, link-local, reserved, or cloud metadata ranges. Because `allow_redirects=True` is enabled, checking only the initial URL would also be insufficient: an attacker-controlled public endpoint could redirect the request to an internal address. Each redirect destination and its resolved addresses must be validated. Although the request uses the `HEAD` method and does not normally download a response body, this does not eliminate SSRF. The operation can still reveal endpoint reachability and status codes, interact with services that process `HEAD`, or trigger behavior in endpoints that do not implement HTTP method semantics safely. The vulnerable functionality is optional and is reached when the user invokes the documented `--check-external-links` option. ### Attack Path 1. An attacker creates or modifies a Markdown file that will be linted. 2. The attacker embeds a link targeting a sensitive destination, such as a loopback service, a private-network host, a link-local metadata endpoint, or a public URL that redirects to one: ```markdown [Internal probe](http://127.0.0.1:8080/admin) ``` 3. A user or automated process runs the linter with external link validation enabled: ` ...[truncated 1455 chars]
Remediation
## Remediation Suggestions 1. Resolve destination hostnames before making requests and reject every address in loopback, private, link-local, multicast, reserved, unspecified, and other non-public ranges for both IPv4 and IPv6. 2. Explicitly block known infrastructure metadata destinations, including link-local metadata addresses and provider-specific metadata hostnames. 3. Disable automatic redirects by default. If redirects are required, validate the scheme, hostname, port, and all resolved IP addresses at every redirect hop. 4. Permit only `http` and `https`, reject embedded credentials, and restrict destination ports to an approved set such as 80 and 443. 5. Prefer an explicit hostname allowlist when the expected link destinations are known. 6. Protect against DNS rebinding by connecting only to the validated resolved address while preserving safe hostname verification for HTTPS. 7. Apply strict connection and total-request timeouts, redirect limits, URL-count limits, and concurrency limits to reduce network resource exhaustion. 8. Run external-link checking in a sandbox with restricted outbound network access and no access to sensitive internal networks. 9. Keep external validation disabled by default and clearly warn that it must not be enabled for untrusted Markdown unless network isolation is in place. 10. Add automated tests covering loopback, RFC 1918 private ranges, IPv6 local ranges, link-local addresses, unusual IP representations, DNS rebinding scenarios, and public-to-private redirects.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Ae1

High
Category
analysis-evasion
Content
./scripts/main.py run --input path/to/file.md
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
./scripts/main.py run --input path/to/file.md
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
./scripts/main.py run --input path/to/file.md
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
./scripts/main.py run --input path/to/file.md
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
./scripts/main.py run --input path/to/file.md
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises file-reading and optional external link validation capabilities, which imply filesystem and network access, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where the runtime may grant broader access than reviewers expect, increasing the risk of unintended file access or outbound requests when processing untrusted markdown paths or links.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The manifest says the skill lints Markdown files for formatting issues, broken links, and style consistency, but this file adds active HTTP requests to external sites via requests.head when --check-external-links is enabled. While checking internal links is local linting behavior, contacting arbitrary external URLs is a separate network capability that is not clearly declared in the stated skill purpose.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
When `--check-external-links` is enabled, the tool performs outbound requests to URLs embedded in markdown without prominently warning users that processing a file may contact third-party hosts. If the markdown is attacker-controlled, this can leak network metadata, trigger requests to tracking or internal endpoints, and surprise users who expected offline linting.

Static analysis

No suspicious patterns detected.