Back to skill

Security audit

qrcode-scan

Security checks for vulnerabilities and agentic risk

Overview

This QR-code skill does what it says, but its URL scanning can make unrestricted network requests from the user's agent environment.

Install only if you are comfortable with the skill fetching URLs from the agent's network context. Prefer local files or base64 input for QR scanning, avoid scanning untrusted URLs, and treat generated WiFi QR images as sensitive because they embed the network password.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:65
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 65–72 and 230–243
Vulnerability Type: Server-Side Request Forgery and unbounded remote resource retrieval
Risk Level: Medium

Vulnerable code:

python
def scan_from_url(self, url: str, format_json: bool = False) -> Union[str, List[str], Dict]:
    try:
        with urllib.request.urlopen(url, timeout=30) as response:
            data = response.read()
        img = Image.open(io.BytesIO(data))
        return self._scan_image(img, format_json)
    except Exception as e:
        raise ValueError(f"Failed to fetch image from URL: {e}")

The URL-fetching method is reached through the following dispatch logic:

python
if input_type == 'file':
    return scanner.scan_from_file(input_data, format_json)
elif input_type == 'url':
    return scanner.scan_from_url(input_data, format_json)
elif input_type == 'base64':
    return scanner.scan_from_base64(input_data, format_json)

if _is_url(input_data):
    return scanner.scan_from_url(input_data, format_json)
elif _is_base64(input_data):
    return scanner.scan_from_base64(input_data, format_json)
else:
    return scanner.scan_from_file(input_data, format_json)

Technical Analysis

The URL scanner passes caller-controlled input directly to urllib.request.urlopen. It does not validate the destination hostname, resolved IP address, port, redirect destinations, response content type, or response size.

A caller can therefore cause the process to send requests from the Agent's network context to loopback, private-network, link-local, or otherwise sensitive HTTP services. Although the response is subsequently interpreted as an image, the outbound request itself is still made. Status differences, response timing, error messages, and image-like responses can expose information about internal services.

Passing input_type='url' directly also bypasses _is_url(), so ...[truncated 2218 chars]

Remediation
View remediation

Remediation Suggestions

  1. Accept only explicit http and https schemes in the network-fetching method itself.
  2. Reject URLs containing embedded credentials or unexpected ports.
  3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses.
  4. Revalidate the resolved destination immediately before connection to reduce DNS-rebinding risk.
  5. Disable automatic redirects or validate the scheme, hostname, port, and resolved address of every redirect target.
  6. Apply an allowlist of trusted image hosts where the deployment model permits it.
  7. Enforce a strict maximum response size by checking Content-Length and reading incrementally with a byte limit.
  8. Require an expected image media type and validate the file signature before invoking image-processing libraries.
  9. Apply connection and read timeouts separately where supported.
  10. Run remote image parsing in a resource-constrained sandbox with current, pinned image-processing dependencies.
  11. Require explicit user authorization before accessing a remote URL and consider disabling URL input in environments where only local QR scanning is required.

T08 · Insecure Dependencies

Note
Location
SKILL.md:48
Finding

Unpinned Third-Party Runtime Dependencies

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, line 48
Vulnerability Type: Unpinned third-party dependencies
Risk Level: Low

Vulnerable installation instruction:

bash
pip install qrcode pillow pyzbar

Technical Analysis

The documented installation command retrieves mutable latest versions of three third-party packages without version constraints, a lock file, or cryptographic hashes. The package names are consistent with the Skill's declared QR-code functionality, and the reviewed project does not use a suspicious package index, dependency name, or remote script installer.

Nevertheless, installations are not reproducible. Future incompatible, vulnerable, or compromised upstream releases could be installed automatically. These packages process attacker-controlled image data and therefore form part of the Skill's security boundary.

Attack Path

  1. A user follows the documented dependency installation command.
  2. pip resolves whichever package versions are current at installation time.
  3. A newly vulnerable, compromised, or unexpectedly changed release is selected.
  4. Package installation logic executes in the user's Python installation context.
  5. The dependency subsequently processes untrusted QR images during normal Skill operation.

This is a supply-chain exposure rather than evidence that the currently named packages are malicious.

Impact Assessment

Impact depends on the nature of a future dependency compromise or vulnerability. It could range from compatibility failures and denial of service to arbitrary code execution with the permissions of the user installing or running the Skill.

The reviewed instructions do not request elevated privileges, and no specific compromised dependency version was identified. Consequently, this finding is assessed as a low-risk hardening issue.

Remediation
View remediation

Remediation Suggestions

  1. Pin every direct dependency to a reviewed version.
  2. Maintain a lock file containing resolved transitive dependencies.
  3. Use hash-verified installation, such as a requirements file with --require-hashes.
  4. Review and update pinned versions through a controlled dependency-update process.
  5. Run vulnerability scanning against direct and transitive dependencies.
  6. Document supported Python and native-library versions, especially the system zbar dependency used by pyzbar.
  7. Install dependencies inside an isolated virtual environment rather than a privileged or system-wide Python environment.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python scripts/main.py scan <input> [--format json]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python scripts/main.py scan <input> [--format json]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python scripts/main.py scan <input> [--format json]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill explicitly supports scanning QR codes from remote URLs, which implies outbound network access, yet it declares no permissions or allowed-tools scope. This creates an undeclared capability gap: operators and users cannot accurately assess what the skill may access, and downstream execution environments may permit unexpected external fetches.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill supports scanning QR codes from remote URLs without warning that it will fetch external resources, which may leak user IP, metadata, or internal network reachability. In some environments, accepting arbitrary URLs can also enable SSRF-like behavior if the runtime can access internal services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill encourages generating QR code image files, including WiFi QR codes that embed SSIDs and passwords, without warning that saved files may persist sensitive credentials on disk or be shared unintentionally. This can expose secrets to other local users, backups, logs, or anyone who receives the generated image.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill will fetch and process arbitrary user-supplied URLs, which expands its behavior from local QR decoding into unrestricted outbound network access. In an agent context this can be abused for SSRF-like access to internal services, unexpected egress, or contacting attacker-controlled endpoints even though the stated purpose is only QR scanning.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The remote fetch path performs network access silently, with no user-facing indication in the core API that scanning a string may cause an outbound request. This increases the chance of unsafe or surprising behavior, including inadvertent data egress and exploitation of the URL fetch path in an agent workflow.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Downloading arbitrary URLs based on user input gives the skill a generic network-retrieval capability unrelated to decoding image bytes. In environments where the agent has network reachability that the user does not, this can be leveraged to probe internal resources or trigger requests to sensitive endpoints.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

Most instructional content, examples, and usage guidance are presented in Chinese, while the file metadata and some command snippets are in English. This effectively imposes a language preference on users without an explicit opt-in or a stated justification that the skill is intended only for Chinese-speaking users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The generator saves image files to an arbitrary output path, which is a file write operation. Although the CLI mentions an output path and later prints a success message, the underlying write path itself has no docstring, comment, or other disclosure explaining that user files will be created or overwritten.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal, suspicious.secret_argv_exposure

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/main.py:194

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:263

Instructions pass high-value credentials through process argv.

Critical
Code
suspicious.secret_argv_exposure
Location
SKILL.md:91