Back to skill

Security audit

Ziptax Sales Tax

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent ZipTax lookup helper, but its bundled script has unsafe address handling that can run injected local commands and it places the API key in a URL for metrics.

Review before installing. Avoid or patch scripts/lookup.sh before using it with user-controlled addresses, prefer direct API calls with header-based authentication, do not put the API key in query strings, and make sure users understand that precise addresses or coordinates will be sent to ZipTax.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lookup.sh:58
Finding

Arbitrary Python Code Execution Through an Unsafely Interpolated Address

Content
View full analysis

Vulnerability Details

File Location: scripts/lookup.sh:58-61
Vulnerability Type: Command injection through dynamically generated Python source code
Risk Level: High

bash
if [[ -n "$ADDRESS" ]]; then
  ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$ADDRESS'))")
  curl -s "${BASE_URL}/request/${VERSION}?address=${ENCODED}" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" | python3 -m json.tool

Technical Analysis

The value of ADDRESS is controlled by the --address command-line argument and is interpolated directly into the source code passed to python3 -c. Shell quoting prevents ordinary shell word splitting, but it does not make the resulting Python program safe.

An address containing a single quote and valid Python syntax can terminate the intended string literal and append arbitrary Python statements. The Python interpreter then executes those statements with the same operating-system identity, environment variables, filesystem permissions, and network access as the script.

This behavior is not necessary for URL encoding. User data should be passed to Python through an argument or standard input, never embedded into executable source code.

Attack Path

  1. An attacker influences the address supplied to the Skill or persuades a user or agent to perform a lookup using a crafted address.
  2. The attacker supplies Python syntax that closes the quoted address and adds a statement, for example:
    text
    ')); __import__("os").system("id"); #
    
  3. The shell expands the crafted value inside the python3 -c argument.
  4. Python parses the injected text as executable source code.
  5. The injected operating-system command runs before the ZipTax request is made.

The payload could replace id with commands that read accessible files, inspect environment variables, make outbound requests, or modify resources writable by the current account.

Impact Assessment

...[truncated 568 chars]

Remediation
View remediation

Remediation Suggestions

Pass the address as a data argument rather than inserting it into Python source:

bash
ENCODED=$(
  python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1]))' \
    "$ADDRESS"
)

Alternatively, use a URL-aware HTTP client that accepts query parameters separately. Apply strict argument-count checks before reading $2, validate lookup inputs according to their expected formats, and add regression tests containing quotes, semicolons, newlines, command substitutions, and Python syntax. The tests should verify that such input is encoded as data and never executed.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lookup.sh:53
Finding

ZipTax API Key Exposed in the Metrics Request URL

Content
View full analysis

Vulnerability Details

File Location: scripts/lookup.sh:53-56
Vulnerability Type: Sensitive credential transmitted in a URL query parameter
Risk Level: Medium

bash
if $METRICS; then
  curl -s "${BASE_URL}/account/metrics?key=${ZIPTAX_API_KEY}" | python3 -m json.tool
  exit 0
fi

Related documentation also endorses query-parameter authentication:

  • SKILL.md:48: Auth: Header X-API-KEY or query param key
  • references/api-reference.md:5-8: API keys may be supplied through a query parameter.

Technical Analysis

The metrics operation embeds ZIPTAX_API_KEY directly into the request URL even though the project already supports the safer X-API-KEY request header. HTTPS protects the URL while it is in transit, but it does not prevent exposure at either endpoint or within local process metadata.

URLs are commonly retained by server access logs, reverse proxies, observability systems, debugging tools, HTTP-client diagnostics, and command histories. While curl is running, its URL argument may also be observable through process-inspection facilities by users or monitoring software with sufficient local access.

Query-string authentication is unnecessary for the declared functionality because the same API accepts header authentication.

Attack Path

  1. A user exports a valid ZIPTAX_API_KEY and runs lookup.sh --metrics.
  2. The script constructs a URL containing the complete secret.
  3. The URL is supplied to curl as a process argument and sent to the ZipTax endpoint.
  4. A local process observer, API access-log reader, reverse-proxy operator, diagnostic collector, or monitoring-system user obtains the recorded URL.
  5. The observer extracts the key parameter and reuses the API credential for unauthorized requests until it is revoked or rotated.

Impact Assessment

Exposure permits unauthorized use of the affected ZipTax account within the permissions associated with the API k ...[truncated 357 chars]

Remediation
View remediation

Remediation Suggestions

Send the API key exclusively through the existing authentication header:

bash
if $METRICS; then
  curl -s "${BASE_URL}/account/metrics" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" |
    python3 -m json.tool
  exit 0
fi

Remove query-parameter authentication recommendations from SKILL.md and references/api-reference.md, and update examples to use X-API-KEY. Ensure that application and proxy logging policies redact authentication headers. Rotate any API key that may already have been captured in URL or process-monitoring logs.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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 (14)

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/lookup.sh (reported line 54)May include surrounding context.

sh
fi

if $METRICS; then
  curl -s "${BASE_URL}/account/metrics?key=${ZIPTAX_API_KEY}" | python3 -m json.tool
  exit 0
fi

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/lookup.sh (reported line 60)May include surrounding context.

sh
if [[ -n "$ADDRESS" ]]; then
  ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$ADDRESS'))")
  curl -s "${BASE_URL}/request/${VERSION}?address=${ENCODED}" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" | python3 -m json.tool
elif [[ -n "$LAT" && -n "$LNG" ]]; then
  curl -s "${BASE_URL}/request/${VERSION}?lat=${LAT}&lng=${LNG}" \

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/lookup.sh (reported line 63)May include surrounding context.

sh
curl -s "${BASE_URL}/request/${VERSION}?address=${ENCODED}" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" | python3 -m json.tool
elif [[ -n "$LAT" && -n "$LNG" ]]; then
  curl -s "${BASE_URL}/request/${VERSION}?lat=${LAT}&lng=${LNG}" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" | python3 -m json.tool
elif [[ -n "$POSTALCODE" ]]; then
  curl -s "${BASE_URL}/request/${VERSION}?postalcode=${POSTALCODE}" \

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/lookup.sh (reported line 66)May include surrounding context.

sh
curl -s "${BASE_URL}/request/${VERSION}?lat=${LAT}&lng=${LNG}" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" | python3 -m json.tool
elif [[ -n "$POSTALCODE" ]]; then
  curl -s "${BASE_URL}/request/${VERSION}?postalcode=${POSTALCODE}" \
    -H "X-API-KEY: ${ZIPTAX_API_KEY}" | python3 -m json.tool
else
  echo "Error: Provide --address, --lat/--lng, or --postalcode" >&2

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents shell and network-based behavior but does not declare any explicit tool scope or permissions boundary. This can lead to overbroad execution in an agent environment, making external requests and shell invocation possible without clear least-privilege constraints or reviewer visibility.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Address Lookup (most accurate)

bash
curl -s "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Drive+Irvine+CA+92618" \
  -H "X-API-KEY: $ZIPTAX_API_KEY"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Address Lookup (most accurate)

bash
curl -s "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Drive+Irvine+CA+92618" \
  -H "X-API-KEY: $ZIPTAX_API_KEY"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Address Lookup (most accurate)

bash
curl -s "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Drive+Irvine+CA+92618" \
  -H "X-API-KEY: $ZIPTAX_API_KEY"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Address Lookup (most accurate)

bash
curl -s "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Drive+Irvine+CA+92618" \
  -H "X-API-KEY: $ZIPTAX_API_KEY"

External Transmission

Medium
Category
Data Exfiltration
Confidence
85% confidence
Finding

The cURL sample shows external transmission of a full street address to a third-party endpoint. External transmission is expected for this skill's purpose, but in an agent context it is still security-relevant because it may send user-provided sensitive location information off-platform, and the example also documents support for query-parameter API keys elsewhere, which increases risk of accidental secret exposure if copied naively.

Content

Scanner excerpt · references/api-reference.md (reported line 109)May include surrounding context.

cURL

bash
curl -X GET "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Drive+Irvine+CA+92618" \
  -H "X-API-KEY: YOUR_API_KEY"

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The Python sample performs an outbound request containing a full address to an external API. This is functionally necessary for the skill, but it still represents a real data egress path for sensitive user location data in an agent environment, especially if callers automatically forward user-entered addresses without notice or policy checks.

Content

Scanner excerpt · references/api-reference.md (reported line 117)May include surrounding context.

python
import requests
resp = requests.get(
    "https://api.zip-tax.com/request/v60",
    params={"address": "200 Spectrum Center Drive Irvine CA 92618"},
    headers={"X-API-KEY": "YOUR_API_KEY"}
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The JavaScript sample sends a full address to a third-party service, creating an external data transmission channel. Within this skill's context that behavior is expected, but it remains a meaningful privacy/security concern because an integrator may unknowingly pass sensitive user location data to the vendor without disclosure, and copied examples may normalize unsafe practices.

Content

Scanner excerpt · references/api-reference.md (reported line 128)May include surrounding context.

JavaScript

javascript
const resp = await fetch(
  "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Drive+Irvine+CA+92618",
  { headers: { "X-API-KEY": "YOUR_API_KEY" } }
);
const data = await resp.json();

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The documentation encourages sending full street addresses and precise coordinates to a third-party API without any privacy, retention, or consent guidance. In the context of an agent skill, this can cause transmission of sensitive location data derived from user input to an external service, increasing privacy and compliance risk if users are not warned or data minimization is not applied.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes the skill as looking up U.S. sales tax rates across U.S. jurisdictions, but the referenced documentation explicitly states that Canadian GST/HST/PST rates are available and EU VAT is in development. That broadens the represented capability beyond the skill's declared U.S.-focused scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.