Back to skill

Security audit

Appian Inspectpkg

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its endpoint handling could send an Appian API key and package files to an unintended or insecure URL.

Review before installing. Use only with a trusted HTTPS Appian base URL, prefer injected environment variables over local appian.json files, check parent directories for unexpected appian.json files before running, and rotate the Appian API key if it may have been used with an untrusted endpoint.

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

Warning
Location
scripts/index.js:90
Finding
Unvalidated Appian Base URL Can Expose API Credentials and Uploaded Package Data## Vulnerability Details **File Location**: `scripts/index.js`, lines 34 and 90–94 **Vulnerability Type**: Unvalidated sensitive-data destination and plaintext transport **Risk Level**: Medium ### Vulnerable Code ```javascript const baseUrl = process.env.APPIAN_BASE_URL?.replace(/\/$/, ''); ``` ```javascript async function sendInspection(credentials, formData) { const res = await fetch(`${credentials.baseUrl}/inspections`, { method: 'POST', headers: { 'appian-api-key': credentials.apiKey }, body: formData, }); ``` ### Technical Analysis `APPIAN_BASE_URL` is accepted directly from the environment or from a discovered `appian.json` configuration file. The value is only normalized by removing one trailing slash. The implementation does not parse and validate the URL, require HTTPS, reject embedded credentials or unusual ports, or constrain the destination to an approved Appian host. The unvalidated value is subsequently used as the destination for an authenticated request containing: - The Appian API key in the `appian-api-key` header. - The user-selected Appian package ZIP. - The optional customization file. - Package and customization filenames. If the URL uses plaintext HTTP, these values may be intercepted or modified by a network-positioned attacker. If an attacker can influence the environment or configuration lookup, the attacker can direct the request to a server they control and receive both the credential and uploaded files. The exposure risk is increased by the configuration lookup behavior at lines 27–33: when credentials are absent from the environment, the program searches the current directory and up to four ancestor directories for `appian.json`. This may cause it to trust configuration outside the intended project directory. ### Attack Path 1. The victim runs the skill without a trusted `APPIAN_BASE_URL` already present in the environment. 2. An att ...[truncated 1617 chars]
Remediation
## Remediation Suggestions 1. Parse the configured endpoint with the standard URL parser and reject malformed values. 2. Require the `https:` protocol before transmitting credentials or package data. 3. Reject URLs containing embedded usernames or passwords. 4. Restrict ports to approved TLS ports unless a documented deployment requirement exists. 5. Where the expected Appian domains are known, enforce an exact hostname or suffix allowlist. Avoid substring-based hostname checks. 6. Restrict fallback configuration loading to an explicit path or the current working directory. Do not silently search ancestor directories. 7. Fail closed when endpoint validation fails, before reading package files or initiating network requests. 8. Document the accepted endpoint format and trusted-host policy. 9. Add tests covering plaintext HTTP URLs, malformed URLs, embedded credentials, deceptive hostnames, unexpected ports, and untrusted ancestor configuration files. Example validation pattern: ```javascript function validateBaseUrl(rawBaseUrl) { let url; try { url = new URL(rawBaseUrl); } catch { throw new Error('APPIAN_BASE_URL must be a valid URL'); } if (url.protocol !== 'https:') { throw new Error('APPIAN_BASE_URL must use HTTPS'); } if (url.username || url.password) { throw new Error('APPIAN_BASE_URL must not contain credentials'); } if (url.search || url.hash) { throw new Error('APPIAN_BASE_URL must not contain a query or fragment'); } // Apply an exact organization-approved hostname policy here. // Example: if (!APPROVED_HOSTS.has(url.hostname)) throw new Error(...); return url.href.replace(/\/$/, ''); } ``` Credentials exposed through a potentially unsafe configuration should be revoked and rotated after the endpoint configuration is corrected.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
console.log(`\nWarnings (${warnings.length}):`);
        for (const w of warnings) console.log(`  [${w.objectName ?? w.objectUuid ?? 'unknown'}] ${w.warningMessage}`);
    } else {
        console.log('No warnings.');
    }

    return { inspectionUuid, status: data.status, expected, errors, warnings };
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares access to sensitive capabilities through metadata and documented behavior: it reads environment variables and performs outbound network requests to an Appian API, but it does not explicitly constrain those capabilities with a tool-scope declaration such as permissions or allowed-tools. This creates an authorization gap where the runtime may grant broader access than reviewers expect, increasing the chance of unintended secret exposure or misuse of network access if the implementation changes or is abused.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/index.js:32