Back to skill

Security audit

match-technology-transfer-opportunities-ip

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed technology-transfer research and reporting workflow with scoped helper scripts and no evidence of hidden execution, persistence, or data exfiltration.

Before installing, be prepared to approve any confidential material handling, external patent/procurement sources, and exact report output paths. Prefer a private output directory you control, avoid shared writable folders, and do not use overwrite options unless you intend to replace an existing file.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/report_generator_patch.py:56
Finding

Predictable Temporary File Permits Symlink-Based Arbitrary File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/report_generator_patch.py, lines 56–64
Vulnerability Type: Predictable temporary file and symlink race
Risk Level: Medium

Vulnerable Code

python
destination.parent.mkdir(parents=True, exist_ok=True)
temporary = destination.with_name(f".{destination.name}.tmp")
if temporary.exists():
    raise FileExistsError(f"Temporary path already exists: {temporary}")
try:
    temporary.write_text(content, encoding="utf-8", newline="\n")
    if destination.exists() and overwrite:
        destination.unlink()

Technical Analysis

The temporary filename is deterministically derived from the destination filename. The code first checks whether that path exists and later opens it through Path.write_text(). These operations are not atomic.

An attacker with write access to the destination directory can create a symbolic link at the predictable temporary pathname after the existence check but before write_text() opens it. Because ordinary file opening follows symbolic links, the linked target will be truncated and replaced with report content.

This is a time-of-check/time-of-use vulnerability. Checking temporary.exists() does not securely reserve the pathname or prevent it from being replaced before use.

Attack Path

  1. A user approves a report destination such as /shared/report.html.
  2. The function derives the temporary path /shared/.report.html.tmp.
  3. The function verifies that the temporary path does not currently exist.
  4. A local attacker with write access to /shared creates /shared/.report.html.tmp as a symbolic link to another file writable by the Skill process.
  5. temporary.write_text() follows the symbolic link.
  6. The linked file is truncated and overwritten with the generated HTML.
  7. The attacker may repeat the race against future report-generation operations.

Successful exploitation requires the attacker to modify ...[truncated 666 chars]

Remediation
View remediation

Remediation Suggestions

  • Create the temporary file atomically inside the destination directory using tempfile.NamedTemporaryFile(delete=False, dir=destination.parent) or os.open() with O_CREAT | O_EXCL.
  • Use O_NOFOLLOW where supported so that opening a symbolic link fails.
  • Write through the securely obtained file descriptor rather than reopening a pathname.
  • Flush and optionally call os.fsync() before atomically installing the completed file.
  • Verify that the temporary object is a regular file owned by the current process.
  • Prefer output directories that are not writable by untrusted local users.
  • Remove temporary files by file descriptor or securely retained randomized pathname during error handling.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/report_generator_patch.py:51
Finding

Non-Overwrite Policy Can Be Bypassed Through a Destination Race

Content
View full analysis

Vulnerability Details

File Location: scripts/report_generator_patch.py, lines 51–68
Vulnerability Type: TOCTOU race in destination replacement
Risk Level: Low

Vulnerable Code

python
def _write_one(content: str, destination: Path, *, overwrite: bool) -> None:
    if destination.exists() and not overwrite:
        raise FileExistsError(f"Refusing to overwrite existing file: {destination}")
    if destination.exists() and not destination.is_file():
        raise OutputError(f"Destination is not a file: {destination}")
    destination.parent.mkdir(parents=True, exist_ok=True)
    temporary = destination.with_name(f".{destination.name}.tmp")
    if temporary.exists():
        raise FileExistsError(f"Temporary path already exists: {temporary}")
    try:
        temporary.write_text(content, encoding="utf-8", newline="\n")
        if destination.exists() and overwrite:
            destination.unlink()
        temporary.replace(destination)
    finally:
        if temporary.exists():
            temporary.unlink()

Technical Analysis

When overwrite=False, the function checks destination existence before creating the report. The later temporary.replace(destination) operation is not conditioned on the destination still being absent.

If another process creates the destination after the initial check, Path.replace() can replace that newly created file. Consequently, the implementation does not atomically enforce its documented guarantee that existing files will never be overwritten without explicit permission.

The repeated calls to destination.exists() also do not bind validation to the object eventually replaced, leaving the operation vulnerable to concurrent filesystem changes.

Attack Path

  1. The caller invokes _write_one() with overwrite=False.
  2. The approved destination does not exist when the first check runs.
  3. The function writes report content to it ...[truncated 849 chars]
Remediation
View remediation

Remediation Suggestions

  • Enforce no-overwrite behavior atomically rather than with a preliminary existence check.
  • Use an operating-system no-replace rename operation where available.
  • Alternatively, create the final destination with exclusive creation semantics such as O_CREAT | O_EXCL, then write through the returned descriptor.
  • If an atomic rename workflow is required, use a platform-specific no-replace primitive and fail when the destination already exists.
  • Avoid unlinking an existing destination before replacement, because that introduces additional race windows and weakens atomicity.
  • Add concurrency tests that create the destination between temporary-file creation and final installation.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/gov_bid_api.py:474
Finding

Procurement CLI Silently Overwrites Caller-Selected Output Files

Content
View full analysis

Vulnerability Details

File Location: scripts/gov_bid_api.py, lines 474–482
Vulnerability Type: Unprotected destructive file write
Risk Level: Low

Vulnerable Code

python
try:
    result = normalize_records(
        load_json(args.input),
        load_mapping(args.mapping),
        items_path=args.items_path,
        strict=args.strict,
    )
    rendered = json.dumps(result_to_dict(result), ensure_ascii=False, indent=2) + "\n"
    if args.output:
        args.output.parent.mkdir(parents=True, exist_ok=True)
        args.output.write_text(rendered, encoding="utf-8")

Technical Analysis

The CLI accepts an output pathname and writes to it with Path.write_text(). That method opens an existing regular file with truncation semantics. The command does not check whether the destination already exists, request confirmation, or require an explicit overwrite option.

It also creates missing parent directories automatically. Although the pathname is supplied through command-line arguments rather than directly derived from procurement records, an Agent integration, wrapper, or user mistake can select an unintended accessible file.

This behavior conflicts with the Skill's stated policy against overwriting existing output without explicit permission.

Attack Path

  1. A caller invokes the procurement normalizer with --output pointing to an existing writable file.
  2. The input and mapping JSON pass normalization.
  3. The command serializes the normalized result.
  4. write_text() opens the selected destination and truncates its previous contents.
  5. The original file is replaced with normalized procurement JSON without an additional overwrite authorization step.

In an automated Agent workflow, an attacker who can influence CLI arguments could exploit this by selecting a sensitive file writable by the Agent. Otherwise, accidental misuse remains the most likely scenario.

Impac

...[truncated 393 chars]

Remediation
View remediation

Remediation Suggestions

  • Reject existing output destinations by default.
  • Add an explicit --overwrite flag and require it before truncating an existing file.
  • Require an absolute, user-approved output pathname when used through the Skill workflow.
  • Open new destinations with exclusive creation semantics to prevent race-condition overwrites.
  • Apply the same secure temporary-file and atomic-installation controls used for report output.
  • Avoid automatically creating arbitrary parent directory trees unless that behavior is separately authorized.
  • Return a clear error containing the destination path when an existing file is rejected.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose centers on technology commercialization analysis and partner prioritization for licensing or joint development. The supplied code does something materially different: it ingests procurement/provider JSON that has already been retrieved elsewhere, validates fields such as ISO dates/country/currency and safe URLs, normalizes records into procurement dataclasses, logs validation issues, filters records, and derives buyer names with supporting record IDs. While one could loosely interpret procurement buyers as potential organizations of interest, the code does not analyze a supplied technology, perform evidence-backed ranking, assess commercialization readiness or risks, or produce an HTML report. This is a clear primary-purpose mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a substantive technology-transfer analysis and matching skill. The actual code chunk is only a supporting persistence/helper library for safely saving already-created HTML reports to user-approved paths. While saving an HTML report is loosely related to the declared reporting output, the primary behavior here is path validation and file writing, not analysis or partner matching. This is therefore a material description-behavior mismatch for this supplied code chunk.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · scripts/report_generator_patch.py (reported line 54)May include surrounding context.

python
def _write_one(content: str, destination: Path, *, overwrite: bool) -> None:
    if destination.exists() and not overwrite:
        raise FileExistsError(f"Refusing to overwrite existing file: {destination}")
    if destination.exists() and not destination.is_file():
        raise OutputError(f"Destination is not a file: {destination}")
    destination.parent.mkdir(parents=True, exist_ok=True)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill references capabilities that can read/write files and use networked connectors, but it does not declare an explicit tool/permission scope. That creates an authorization ambiguity: a host may grant broader access than intended, enabling exfiltration of confidential technology materials or unauthorized file writes if the skill is executed in a permissive environment. In this context, the risk is heightened because the skill explicitly handles confidential IP, ownership, and commercialization data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest describes a skill for evaluating technologies, ranking potential licensees/acquirers/partners, assessing transfer readiness and risks, and generating decision-support reports. This file instead implements normalization, filtering, and buyer-candidate extraction for procurement/bid records from external providers, which is a different business function centered on public procurement data handling rather than technology-transfer opportunity matching.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The module derives buyer candidate organizations from procurement records, effectively surfacing procurement counterparties as targets based on bid data. While external evidence gathering can support commercialization research, a dedicated buyer-candidate extraction capability from procurement feeds is not explicitly justified by the manifest's stated purpose of technology-transfer matching and readiness/risk assessment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The generated document always uses <html lang="en">, even though validation requires metadata.output_language and the function docstring describes the report as localized. This creates a natural-language/locale policy issue because the skill forces English markup rather than offering or applying the user-specified language.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.