Back to skill

Security audit

Grant Proposal Assistant

Security checks for vulnerabilities and agentic risk

Overview

This grant-writing skill is mostly coherent, but its script can read or overwrite arbitrary local files through user-supplied paths without enforcing the workspace limits its own documentation calls for.

Review before installing. Use this only in a sandboxed workspace and pass explicit proposal/report paths you control. Avoid giving it absolute paths or traversal paths, and do not point --output at any existing or important file until the script adds path validation and overwrite protection.

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

Warning
Location
scripts/main.py:635
Finding

Unrestricted User-Controlled File Read

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:635-642
Vulnerability Type: Arbitrary file read through an unrestricted input path
Risk Level: Medium

Vulnerable Code:

python
if args.review:
    if not args.input:
        print("Error: --input required for review mode", file=sys.stderr)
        sys.exit(1)

    content = Path(args.input).read_text()
    result = assistant.review_proposal(content)

Technical Analysis

The --input argument is controlled by the caller and is passed directly to Path.read_text() without path normalization, workspace confinement, symlink validation, regular-file validation, or a file-size limit. Absolute paths and traversal sequences such as ../ are therefore accepted.

This violates least-privilege expectations for a proposal-reviewing Skill, which should only access proposal files inside an authorized workspace. It also conflicts with the path-validation and workspace-restriction objectives documented in SKILL.md.

The review report does not reproduce the complete input, which limits direct disclosure. Nevertheless, processing a sensitive file can reveal derived information such as its word count, estimated page count, detected section names, keywords, and checklist results. Large or special files may also cause resource exhaustion or unhandled exceptions.

Attack Path

  1. An attacker persuades the user or Agent to review a path outside the authorized workspace.
  2. The Skill is invoked with an argument such as:
    bash
    python3 scripts/main.py --review --input ../../sensitive-file --output report.md
    
  3. Path(args.input).read_text() resolves and reads the external file using the operating-system permissions of the Skill process.
  4. The review logic analyzes the file and exposes derived metadata in the generated report.
  5. If the selected file is very large, the unrestricted read may also consume excessive memory and CPU.

...[truncated 511 chars]

Remediation
View remediation

Remediation Suggestions

  1. Define an explicit workspace root and resolve the supplied path before use:
    python
    workspace = Path.cwd().resolve()
    input_path = Path(args.input).resolve(strict=True)
    
    if not input_path.is_relative_to(workspace):
        raise ValueError("Input file must be inside the authorized workspace")
    
  2. Reject symbolic links when they are not explicitly required, and verify that the target is a regular file.
  3. Permit only expected proposal file types where practical.
  4. Check file size before reading and enforce a reasonable maximum.
  5. Specify and safely handle text encoding and decoding errors.
  6. Catch filesystem exceptions and return sanitized errors without exposing unnecessary host details.
  7. Apply the same validation in both command-line and library-facing interfaces.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:662
Finding

Arbitrary File Overwrite Through Unrestricted Output Path

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:662-681
Vulnerability Type: Arbitrary file creation or overwrite through an unrestricted output path
Risk Level: Medium

Vulnerable Code:

python
if args.output:
    Path(args.output).write_text(output)
    print(f"Review report saved to: {args.output}")
else:
    print(output)

return

# Generation mode
if not args.section:
    print("Error: --section required (or use --review)", file=sys.stderr)
    sys.exit(1)

# Generate content
content = assistant.generate_section(args.section, num_aims=args.num_aims)

# Output
if args.output:
    Path(args.output).write_text(content)
    print(f"Generated {args.section} section saved to: {args.output}")
else:
    print(content)

Technical Analysis

Both review and generation modes pass the caller-controlled --output value directly to Path.write_text(). The code does not restrict output to an authorized workspace, reject traversal or absolute paths, detect symbolic links, prevent overwriting existing files, or use atomic file creation.

Path.write_text() truncates an existing target before writing. Consequently, a caller can replace any file writable by the operating-system account running the Skill. Symlinks can also redirect a seemingly safe workspace path to a target elsewhere on the filesystem.

Although generated content is fixed proposal text rather than attacker-selected executable code, replacing configuration, source, shell initialization, or application data files can still cause denial of service, data loss, or secondary behavior changes.

Attack Path

  1. An attacker supplies or recommends an output path outside the proposal workspace.
  2. The Agent invokes the Skill with a command such as:
    bash
    python3 scripts/main.py --section aims --output ../../valuable-file
    
  3. The script calls Path(args.output).write_text(content).
  4. If the tar ...[truncated 913 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve output paths against a dedicated workspace and reject targets outside it:
    python
    workspace = Path.cwd().resolve()
    output_path = (workspace / args.output).resolve()
    
    if not output_path.is_relative_to(workspace):
        raise ValueError("Output file must be inside the authorized workspace")
    
  2. Reject absolute paths and traversal components before resolution as defense in depth.
  3. Reject symlink targets and verify that every existing parent directory remains inside the workspace.
  4. Refuse to overwrite existing files by default. Require a deliberate --force option when replacement is necessary.
  5. Create output atomically using a securely created temporary file in the destination directory, followed by os.replace().
  6. Set restrictive permissions where generated proposals may contain sensitive research or personnel information.
  7. Handle filesystem errors with sanitized messages.
  8. Add tests for absolute paths, ../ traversal, symlink escapes, existing-file overwrites, and paths outside the configured workspace.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • 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 (6)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · references/NSF_template.md (reported line 31)May include surrounding context.

md
### 3. Project Description (15 pages maximum)

#### Content Requirements
- Clear statement of objectives
- Relationship to current state of knowledge
- Plan of work
- Expected significance

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises and documents file read/write behavior but does not declare any explicit tool scope such as permissions or allowed-tools. This creates a policy and containment gap: an agent or reviewer cannot reliably determine what filesystem operations are intended, and the documented support for user-supplied input/output paths increases the chance of unintended file access if implementation-side validation is weak or absent.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script writes a review report to the user-supplied output path with no confirmation prompt and no indication whether an existing file may be overwritten. This is a safety-relevant file modification operation, and the surrounding code does not provide a warning beyond a post-write success message.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

In generation mode, the script writes generated proposal content directly to the provided output path without confirming the action or warning about possible overwrite. This is a file write operation lacking the forms of disclosure required by the rule.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The script reads an arbitrary input file path directly in review mode, but there is no user-facing notice about accessing local file contents beyond the argument name itself. Under the code-file warning rule, file access affecting user data should have some disclosure such as a comment, docstring, or visible prompt/log explaining the action.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.