Back to skill

Security audit

Domain WHOIS Lookup

Security checks for vulnerabilities and agentic risk

Overview

This domain lookup skill is mostly coherent, but its optional screenshot helper can be pointed at local or private network targets, so it needs review before installation.

Review or disable the screenshot feature before installing, especially in environments with access to internal dashboards, localhost services, cloud metadata, or private networks. The domain lookup portions are purpose-aligned, but screenshot capture should be restricted to public registrable hostnames and fixed in-skill output paths.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/domain-screenshot.js:27
Finding

Browser-Based Server-Side Request Forgery Through Unrestricted Domain Navigation

Content
View full analysis

Vulnerability Details

File Location: scripts/domain-screenshot.js:27-31, 69-76
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: High

Vulnerable Code

js
const domain = process.argv[2] || 'example.com';

// Security: Validate domain - only allow alphanumeric, hyphen, dot
const safeDomain = domain.replace(/[^a-zA-Z0-9.-]/g, '');
if (safeDomain !== domain) {
  fail('Screenshot failed: Invalid characters in domain');
}
js
// Try https first, then http
const urls = ['https://' + safeDomain, 'http://' + safeDomain];
let navigated = false;

for (const url of urls) {
  try {
    await page.goto(url, { waitUntil: 'load', timeout: 30000 });
    navigated = true;
    break;
  } catch (_) {
    // try next
  }
}

Technical Analysis

The validation only restricts the characters used in the destination. It does not establish that the supplied destination is a public Internet domain. Inputs such as localhost, 127.0.0.1, private IPv4 addresses, IPv6-derived hostnames, and attacker-controlled domains resolving to internal addresses can pass this check.

Playwright navigation also follows HTTP redirects by default. Consequently, an initially public hostname can redirect the browser to a loopback, private, link-local, or otherwise restricted endpoint. The script does not validate DNS resolution results or redirect destinations before allowing Chromium to connect.

The Skill instructions state that a successful screenshot is subsequently sent through the messaging tool. Therefore, content rendered from an internal service may be captured and returned to the requester. This network access exceeds the least privilege required to inspect public domains.

Attack Path

  1. An attacker asks the Skill to inspect a syntactically valid internal destination, such as 127.0.0.1, or an attacker-controlled public hostname.
  2. The input passes the character-based v ...[truncated 1190 chars]
Remediation
View remediation

Remediation Suggestions

  • Require a registrable public hostname rather than accepting arbitrary host-like strings or IP literals.
  • Resolve the hostname before navigation and reject every result in loopback, private, link-local, multicast, unspecified, documentation, reserved, and other non-public IPv4 and IPv6 ranges.
  • Re-resolve and validate the destination immediately before connection to reduce DNS-rebinding exposure.
  • Disable redirects where possible. If redirects are required, inspect and validate every redirect destination before navigation continues.
  • Use Playwright request interception to block requests to non-public addresses, including subresources initiated by the loaded page.
  • Consider running Chromium in an isolated network namespace that can access only public HTTP and HTTPS destinations.
  • Apply the same public-address policy to all WHOIS, DNS, TLS, and browser-related stages rather than relying solely on character validation.
  • Add tests covering loopback addresses, RFC 1918 addresses, link-local addresses, IPv6 private ranges, DNS rebinding, and public-to-private redirects.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/domain-screenshot.js:34
Finding

Screenshot Output Path Containment Bypass

Content
View full analysis

Vulnerability Details

File Location: scripts/domain-screenshot.js:34-45
Vulnerability Type: Improper Path Validation and Arbitrary File Write
Risk Level: Medium

Vulnerable Code

js
// Build output path relative to script directory
const outputPath = outputArg
  ? (path.isAbsolute(outputArg) ? outputArg : path.resolve(baseDir, outputArg))
  : path.resolve(baseDir, defaultOutput);

// Security: Ensure output path is within baseDir
if (!outputPath.startsWith(baseDir)) {
  fail('Screenshot failed: Path traversal attempt detected');
}

// Ensure output directory exists
const dir = path.dirname(outputPath);
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, { recursive: true });
}

Technical Analysis

The script uses a string-prefix comparison to determine whether the output path is inside the Skill root. A path sharing the same textual prefix is not necessarily a descendant of that directory.

For example, if baseDir is /tmp/artifact, a resolved path such as /tmp/artifact-evil/screenshot.png starts with /tmp/artifact and therefore passes the check, despite being outside the authorized directory.

Both absolute and relative caller-controlled output paths are accepted. After the inadequate validation, the script recursively creates the destination directory and later passes the path to page.screenshot, which writes or overwrites the file. The validation also does not protect against symlinked path components that resolve outside the Skill root.

Attack Path

  1. An attacker or untrusted caller invokes the helper with a valid domain and a crafted output argument.
  2. The output argument resolves to a sibling path whose name begins with the Skill root name, such as ../artifact-evil/result.png when the root directory is named artifact.
  3. path.resolve produces an outside path that still has the same textual prefix as baseDir.
  4. The startsWith(baseDir) check incorrec ...[truncated 989 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove the caller-controlled output argument if it is unnecessary and always write to a fixed, dedicated screenshot directory.
  • If configurable paths are required, compare filesystem paths structurally rather than by textual prefix. Use path.relative(baseDir, outputPath) and reject a result that is absolute, equals .., or begins with .. followed by the platform path separator.
  • Resolve the real path of the destination's nearest existing parent and verify that it remains under the real Skill root.
  • Reject symlinked path components, or open the destination using platform protections that prevent symlink following.
  • Generate unpredictable filenames and use exclusive file creation where overwriting is not required.
  • Apply restrictive permissions to the screenshot directory.
  • Add tests for sibling-prefix paths, relative traversal, absolute outside paths, symlink escapes, and platform-specific separators.
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
87% confidence
Finding

The skill declares operational behavior that uses external capabilities and at least environment-aware/runtime-dependent tooling, but it does not declare a restrictive tool scope such as permissions or allowed-tools. That creates ambiguity about what the agent may access at execution time and can allow broader-than-intended tool or environment usage, especially in runtimes that default to permissive access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script performs outbound web requests to the supplied domain via Playwright navigation and writes a screenshot file to disk, but it provides no prior warning, confirmation, or descriptive comment/docstring disclosing these side effects to the user. The only visible output is a success message after the file has already been written.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This is a markdown file, so vague-trigger review applies. The skill gives positive examples of accepted inputs, but it does not define boundaries or negative examples for when whois requests should not invoke the skill, which can make activation scope less precise.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.