Back to skill

Security audit

Incident Postmortem

Security checks for vulnerabilities and agentic risk

Overview

This skill coherently generates incident postmortem reports from user-provided files, but HTML output should only be used with trusted content.

Install only if you are comfortable letting the skill read incident files you explicitly provide. Prefer Markdown or JSON output for untrusted logs or incident data, and treat generated HTML as unsafe to open or host unless the inputs are trusted or the HTML is sanitized first.

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/generate_postmortem.py:416
Finding

Stored HTML and JavaScript Injection in Generated Reports

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_postmortem.py, lines 416–490
Vulnerability Type: Unescaped user-controlled content in generated HTML
Risk Level: Medium

Vulnerable Code

python
def generate_html(markdown_content, title):
    """Wrap markdown content in a simple HTML template."""
    # Simple markdown-to-HTML conversion for key elements
    html = markdown_content

    # Headers
    html = re.sub(r'^# (.+)$', r'<h1>\1</h1>', html, flags=re.MULTILINE)
    html = re.sub(r'^## (.+)$', r'<h2>\1</h2>', html, flags=re.MULTILINE)
    html = re.sub(r'^### (.+)$', r'<h3>\1</h3>', html, flags=re.MULTILINE)

    # Bold
    html = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', html)
    # Italic
    html = re.sub(r'_(.+?)_', r'<em>\1</em>', html)
    # Code
    html = re.sub(r'`(.+?)`', r'<code>\1</code>', html)

    # Lists
    html = re.sub(r'^- (.+)$', r'<li>\1</li>', html, flags=re.MULTILINE)

    # Tables (simple conversion)
    def convert_table(match):
        lines = match.group(0).strip().split('\n')
        rows = []
        for i, line in enumerate(lines):
            if '---' in line:
                continue
            cells = [c.strip() for c in line.strip('|').split('|')]
            tag = 'th' if i == 0 else 'td'
            row = ''.join(f'<{tag}>{c}</{tag}>' for c in cells)
            rows.append(f'<tr>{row}</tr>')
        return f'<table>{"".join(rows)}</table>'

    html = re.sub(r'(\|.+\|(?:\n\|.+\|)*)', convert_table, html)

    # Paragraphs (lines not already wrapped)
    lines = html.split('\n')
    processed = []
    for line in lines:
        if line.strip() and not line.strip().startswith('<') and not line.strip().startswith('*'):
            processed.append(f'<p>{line}</p>')
        else:
            processed.append(line)
    html = '\n'.join(processed)

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scal
...[truncated 2865 chars]
Remediation
View remediation

Remediation Suggestions

  1. Escape untrusted content before constructing HTML. Use html.escape() for text inserted into HTML, including the document title:

    python
    from html import escape
    
    safe_title = escape(str(title), quote=True)
    
  2. Do not use regex substitutions as a Markdown security mechanism. Use a maintained Markdown renderer configured to reject or escape raw HTML.

  3. Sanitize rendered HTML with an allowlist sanitizer. Permit only required formatting tags and safe attributes. Remove at minimum:

    • script, iframe, object, embed, and style elements.
    • Inline event handlers such as onclick and onerror.
    • Dangerous URL schemes such as javascript:.
    • Unnecessary external-resource attributes.
  4. Keep values separate from markup. Escape incident fields, timeline event text, action-item values, and log messages at the point where they enter an HTML text or attribute context.

  5. Add regression tests covering payloads in every attacker-controlled source, including:

    • Incident title and summary.
    • Timeline event text.
    • Action-item cells.
    • Parsed log messages.
    • Closing-tag payloads such as </title>.
    • Event-handler payloads such as <img src=x onerror=alert(1)>.
  6. Apply defense in depth when reports are served over HTTP by using a restrictive Content Security Policy, for example one that blocks inline scripts and limits resource origins. CSP should supplement, not replace, escaping and sanitization.

Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill instructs use of local log files, output file generation, and references JSON/HTML processing, which implies file read and file write capability, yet it declares no explicit tool scope or permission boundaries. That creates unnecessary ambient authority: an agent may read arbitrary files or write outputs in unintended locations when the skill is invoked, increasing the risk of data exposure or filesystem misuse.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases are very broad and match common operational language such as "incident report," "RCA," and "incident review," which can cause the skill to activate in contexts where the user did not intend log parsing or document generation. In an agent environment, over-broad activation can lead to unnecessary access to sensitive incident data or unintended file operations tied to the skill workflow.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated HTML hard-codes lang="en", which imposes a specific language/locale in output regardless of the user's preferences or incident content. This matches the policy category for language or locale constraints without opt-in or documented justification.

Content

No source excerpt is available for this finding.