Back to skill

Security audit

Project Narrator

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed project-documentation tool, but its optional URL checker can contact arbitrary URLs from a narrative file and its output intentionally centralizes sensitive operational metadata.

Install only for repositories where creating a sensitive internal project inventory is acceptable. Review PROJECT-NARRATIVE.md before committing or sharing it, avoid storing real secrets in it, and do not use --check-urls on untrusted narratives or in networks where localhost, intranet, or cloud metadata endpoints are reachable.

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/audit.py:355
Finding

Optional URL Validation Permits Blind Server-Side Request Forgery

Content
View full analysis
\]]+)", content)) return urls ``` ```python def check_urls(content): """Check that URLs in the narrative are reachable.""" findings = [] urls = extract_urls(content) for url in sorted(urls): try: req = urllib.request.Request(url, method="HEAD") req.add_header("User-Agent", "project-narrator-audit/1.0") urllib.request.urlopen(req, timeout=10) except urllib.error.HTTPError as e: if e.code >= 400: findings.append(Finding( "WARNING", "URL Check", f"URL returned HTTP {e.code}: {url}" )) except (urllib.error.URLError, OSError, ValueError): findings.append(Finding( "WARNING", "URL Check", f"URL unreachable: {url}" )) return findings ``` ```python if check_urls_flag: print("Checking URLs (this may take a moment)...") all_findings.extend(check_urls(content)) ``` ### Technical Analysis When `--check-urls` is enabled, the audit script extracts arbitrary HTTP and HTTPS URLs from the narrative and passes them directly to `urllib.request.urlopen`. It does not validate the destination hostname or resolved IP address. The implementation does not reject: - Loopback addresses such as `127.0.0.1` or `::1` - RFC1918 private network addresses - Link-local addresses such as `169.254.0.0/16` - Cloud instance metada ...[truncated 2711 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (24)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `scripts/generate.py` in the project root to produce a scaffold

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `scripts/generate.py` in the project root to produce a scaffold

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
1. Run `scripts/generate.py` in the project root to produce a scaffold

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `scripts/audit.py` against the project root

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `scripts/audit.py` against the project root

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `scripts/audit.py` against the project root

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `scripts/audit.py` against the project root

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/narrative-template.md (reported line 5)May include surrounding context.

md
*Last updated: YYYY-MM-DD*

<!-- 
  This is your project's single source of truth.
  If everything disappeared except this file, could someone rebuild the project?
  If yes, this narrative is complete.

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/narrative-template.md (reported line 55)May include surrounding context.

md
## Infrastructure

**Hosting:** <!-- Where does this run? -->
**Database:** <!-- What database(s)? Where hosted? -->
**CDN/Assets:** <!-- Static hosting, CDN, image pipeline? -->
**DNS:** <!-- Registrar, nameservers -->

Hidden Instructions

High
Category
Prompt Injection
Confidence
87% confidence
Finding

This section asks maintainers to record 'Services & accounts' including 'Account/ID' values in a single narrative file. Centralizing provider names, purposes, and account identifiers can materially aid reconnaissance, account targeting, phishing, and cloud-environment enumeration if the document is exposed or broadly shared.

Content

Scanner excerpt · references/narrative-template.md (reported line 64)May include surrounding context.

md
**Services & accounts:**
| Service | Purpose | Account/ID |
|---------|---------|------------|
| <!-- e.g., Cloudflare --> | <!-- Workers, DNS --> | <!-- account ID --> |

## Pipeline / Workflow

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/narrative-template.md (reported line 87)May include surrounding context.

md
-->

**Rollback:**
<!-- How do you undo a bad deploy? -->

## API Routes

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/narrative-template.md (reported line 95)May include surrounding context.

md
| Method | Path | Description |
|--------|------|-------------|
| <!-- GET --> | <!-- /api/health --> | <!-- Health check --> |

## Scripts

Hidden Instructions

High
Category
Prompt Injection
Confidence
89% confidence
Finding

This configuration section instructs authors to list every environment variable, what it controls, and where it is stored, including examples like .env and wrangler.toml. Even without secret values, a complete inventory of environment variables and storage locations provides attackers with a map of secret material, deployment configuration, and likely attack paths, especially in a 'single source of truth' document.

Content

Scanner excerpt · references/narrative-template.md (reported line 116)May include surrounding context.

md
| Variable | Purpose | Where stored |
|----------|---------|-------------|
| <!-- DATABASE_URL --> | <!-- D1 connection --> | <!-- .env / wrangler.toml --> |

**Config files:**
- <!-- wrangler.toml — Cloudflare Workers config -->

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/narrative-template.md (reported line 116)May include surrounding context.

md
| Variable | Purpose | Where stored |
|----------|---------|-------------|
| <!-- DATABASE_URL --> | <!-- D1 connection --> | <!-- .env / wrangler.toml --> |

**Config files:**
- <!-- wrangler.toml — Cloudflare Workers config -->

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/audit.py (reported line 32)May include surrounding context.

python
".py", ".sh", ".ts", ".js", ".jsx", ".tsx", ".json", ".md", ".html",
    ".yaml", ".yml", ".toml", ".css", ".scss", ".sql", ".rs", ".go",
    ".rb", ".php", ".java", ".kt", ".swift", ".c", ".cpp", ".h",
    ".vue", ".svelte", ".env", ".lock", ".txt", ".cfg", ".ini",
    ".xml", ".csv", ".graphql", ".prisma", ".tf", ".hcl",
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README explicitly promotes scanning the workspace and generating a comprehensive project narrative, including architecture, infrastructure, API routes, scripts, known issues, and locations of credentials/IDs, but it does not warn that sensitive repository metadata and operational details may be aggregated into a durable output file. In a documentation/disaster-recovery skill, this increases the chance of over-collection and accidental disclosure because users may treat the generated file as safe to commit, share, or hand to other developers or AI agents.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill describes use of file read/write, shell commands, and an external CLI, but it does not declare any explicit tool scope or permissions boundaries. In practice this can lead to overbroad execution if a host agent auto-grants default capabilities, increasing the blast radius for workspace modification, command execution, and possible external interaction.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad and include generic terms like 'fresh eyes', 'project health check', and 'documentation audit', which may invoke the skill in contexts the user did not intend. Because the skill can scan repositories, run shell commands, and write files, accidental invocation could expose sensitive project metadata or cause unwanted modifications.

Content

No source excerpt is available for this finding.

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

  1. Run scripts/audit.py against the project root
  2. Review findings by severity (CRITICAL > WARNING > INFO)
  3. Present findings to the user — don't auto-fix without asking
bash
python3 scripts/audit.py --workspace /path/to/project

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

md
6. Flag sections that likely need manual review based on what changed
7. Update the "Last updated" date

**The agent should not blindly rewrite sections** — flag what changed and let the user decide how to update the narrative prose.

### `narrator report`

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The 'Key Principles' section states narratives are 'always regenerated from scratch — never patched or appended' and that every regeneration automatically archives the previous version. Earlier in the same file, narrator update is explicitly defined as an incremental workflow that reads the existing narrative, updates the changelog, flags sections for review, and updates the last-updated date, which contradicts the absolute claim.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The optional URL-checking feature makes outbound HTTP requests to every URL found in the narrative, which extends the skill's behavior beyond local workspace auditing into network interaction. Because PROJECT-NARRATIVE.md is treated as input, a malicious or untrusted narrative could trigger requests to attacker-controlled or internal URLs, causing SSRF-like behavior, information disclosure through network metadata, or unexpected egress from restricted environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Even though URL checking is behind a flag, the implementation contacts all extracted URLs without meaningful disclosure of the privacy and security implications of doing so. If users run the option on untrusted narratives, it can leak that the audit was run, send requests to attacker infrastructure, or probe sensitive internal endpoints referenced in documentation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/generate.py (reported line 27)May include surrounding context.

python
def run_cmd(cmd, cwd=None):
    """Run a shell command, return stdout or empty string on failure."""
    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=15, cwd=cwd
        )
        return result.stdout.strip() if result.returncode == 0 else ""

Static analysis

No suspicious patterns detected.