Back to skill

Security audit

Servicenow Docs

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a ServiceNow documentation helper, but one article-fetch tool can request arbitrary URLs from the agent runtime instead of being limited to ServiceNow documentation sites.

Review before installing. This skill should be used only in an environment where outbound network access is restricted or after the article-fetch tool is changed to allow only HTTPS ServiceNow documentation hosts and to validate redirects. The dependency should also be pinned for more reproducible installs.

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

Error
Location
logic.ts:318
Finding
Server-Side Request Forgery Through Unrestricted Article URL Fetching<![CDATA[ ## Vulnerability Details **File Location**: `logic.ts:318-327` and `logic.ts:476-482` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```ts async function getArticle(url: string): Promise<string> { try { // Fetch from Zoomin API with proper headers to get JSON with full HTML const response = await fetch(url, { headers: { 'Accept': 'application/json', }, redirect: 'follow', }); ``` The tool definition exposes the URL directly to callers: ```ts export const servicenow_get_article: ToolDef = { name: 'servicenow_get_article', description: 'Fetch the full content of a ServiceNow documentation article', schema: z.object({ url: z.string().describe('The article URL from search results'), }), execute: async (args: unknown) => { const { url } = args as { url: string }; return getArticle(url); }, }; ``` ### Technical Analysis The `servicenow_get_article` tool accepts an arbitrary string as its `url` argument and passes it directly to the server-side `fetch` API. The implementation does not: - Parse and validate the supplied URL. - Require the HTTPS protocol. - Restrict requests to approved ServiceNow hostnames. - Reject localhost, private, link-local, loopback, or reserved network addresses. - Restrict destination ports. - Resolve and validate destination IP addresses. - Validate redirect destinations. The request explicitly uses `redirect: 'follow'`. Consequently, even validation of only the initial hostname would remain vulnerable if an approved or attacker-controlled endpoint redirected the request to an internal destination. The `toPublicUrl()` helper does not mitigate this vulnerability because it is only used when formatting returned output. It neither validates nor transforms the URL before the network request occurs. ### Attack Path 1. An attacker or untrusted prompt invokes `servicenow_get_article` with a URL targeting an intern ...[truncated 1424 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Use an exact hostname allowlist** - Parse input with `new URL(url)`. - Require `https:`. - Permit only the exact ServiceNow documentation hosts required by the feature, such as `docs.servicenow.com` and the explicitly approved Zoomin backend. - Do not use suffix checks that could accept names such as `docs.servicenow.com.attacker.example`. 2. **Avoid arbitrary URLs** - Prefer accepting a validated article identifier or relative documentation path. - Construct the final ServiceNow URL internally from a trusted base URL. 3. **Control redirects** - Set `redirect: 'manual'` and reject redirects, or validate every redirect destination using the same protocol, hostname, port, and address rules. - Apply a strict maximum redirect count. 4. **Block internal network destinations** - Resolve the hostname and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges. - Repeat validation when connecting and after every redirect to mitigate DNS rebinding and time-of-check/time-of-use issues. - Enforce outbound network restrictions at the container, firewall, or proxy layer as defense in depth. 5. **Restrict ports and response handling** - Permit only TCP port 443. - Set request timeouts and response-size limits. - Validate the response content type and expected JSON structure before processing it. 6. **Strengthen schema validation** - Replace `z.string()` with a URL schema plus application-level validation. - Return a generic validation error that does not reveal internal network details. 7. **Add security tests** - Test rejection of `localhost`, loopback addresses, RFC1918 addresses, link-local metadata addresses, IPv6 local addresses, encoded IP representations, embedded credentials, non-HTTPS schemes, nonstandard ports, deceptive subdomains, and redirects to blocked destinations. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill exposes multiple network-capable operations against external ServiceNow endpoints but does not declare any explicit tool scope such as allowed-tools or permissions. This weakens least-privilege controls and can allow broader-than-intended outbound access or make runtime policy enforcement ambiguous, especially in systems that rely on manifest metadata to constrain tool usage.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The article fetch tool accepts a user-provided URL string and passes it directly to fetch() without validating that it belongs to an expected ServiceNow documentation domain. This creates a server-side request capability that can be abused to access arbitrary external resources, and depending on the runtime/network environment may enable SSRF against internal services or unauthorized outbound requests.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The code formats dates with a hard-coded 'en-US' locale, which imposes a specific language/locale choice in user-visible output. This appears again later in the file and there is no opt-in, fallback, or documentation explaining why US English formatting is required.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This user-facing date formatting again forces the 'en-US' locale without offering the user a choice. Under the policy, locale constraints should be optional or clearly justified for the skill's purpose.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"main": "SKILL.md",
  "type": "module",
  "dependencies": {
    "zod": "^4.3.5"
  }
}
Confidence
93% confidence
Finding
The dependency is specified with a caret range (^4.3.5) rather than being pinned to an exact version, which makes builds non-reproducible and can silently pull in newer releases. In a security context this increases supply-chain uncertainty and can unexpectedly introduce vulnerable or malicious package versions during installation.

Unverifiable Dependency: zod has 1 known advisory(ies) (CVE-2023-4316 (Zod denial of service vulnerability)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
87% confidence
Finding
The manifest references zod without an exact version pin, while zod has a known advisory history, so it is not possible to verify from this file alone whether the installed version is affected. This ambiguity creates avoidable exposure to a known vulnerable dependency and weakens assurance that the skill is installed with a safe release.

Static analysis

No suspicious patterns detected.