Back to skill

Security audit

17track package tracking

Security checks for vulnerabilities and agentic risk

Overview

This is a real 17TRACK parcel-tracking skill, but its optional webhook handling can accept forged updates and it may send local parcel labels to 17TRACK without making that clear.

Install only if you are comfortable giving the skill a 17TRACK API token, storing parcel data in a workspace-local SQLite database, and sending tracking numbers plus carrier parameters to 17TRACK. Avoid public webhook exposure unless the signature-enforcement bug is fixed; prefer polling. Do not put private details in labels unless you also explicitly set a non-sensitive --tag or the label-to-tag behavior is changed.

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/track17.py:1234
Finding
Webhook signatures are detected but not enforced<![CDATA[ ## Vulnerability Details **File Location**: `scripts/track17.py:1234-1310` **Vulnerability Type**: Authentication bypass in webhook ingestion **Risk Level**: High ### Vulnerable Code ```python sig_valid: Optional[bool] = None if secret and sig_value: expected = compute_webhook_signature(raw_body, secret) sig_valid = expected.lower() == sig_value.lower() payload_sha = store_payload( conn, raw_body=raw_body, source=source, event_type=None, number=None, carrier=None, signature=sig_value, signature_valid=sig_valid, ) payload = parse_webhook_payload(raw_body) # 17TRACK webhook structure: { event: "TRACKING_UPDATED", data: {...} } event_type = payload.get("event") data = payload.get("data") # Update payload record with extracted basics (best-effort) number = None carrier = None if isinstance(data, dict): number = data.get("number") carrier = data.get("carrier") conn.execute( "UPDATE payloads SET event_type=?, number=?, carrier=? WHERE sha256=?", (event_type, number, carrier, payload_sha), ) conn.commit() if not isinstance(data, dict): return False, f"Stored payload {payload_sha} (no data object)" number_s = _normalise_number(str(data.get("number") or "")) carrier_i = int(data.get("carrier") or 0) tag = str(data.get("tag") or "") param = str(data.get("param") or "") # Ensure package exists pkg = conn.execute( "SELECT * FROM packages WHERE number=? AND carrier=? AND param=? ORDER BY id DESC LIMIT 1", (number_s, carrier_i, param), ).fetchone() if not pkg: pkg = upsert_package( conn, number=number_s, carrier=carrier_i, param=param, label=None, tag=tag, lang=os.environ.get("TRACK17_LANG") or "en", api_registered=True, ) # Use the data object as the response item; it includes track_info. changed, summary = apply_update_from_trackinfo( conn, package_row=pkg, response_item=data, raw_payload_sha=payloa ...[truncated 2734 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce signature authentication before storing or processing a payload when `TRACK17_WEBHOOK_SECRET` is configured: ```python import hmac if secret: if not sig_value: raise Track17Error("Webhook signature is required") expected = compute_webhook_signature(raw_body, secret) if not hmac.compare_digest(expected.lower(), sig_value.lower()): raise Track17Error("Invalid webhook signature") ``` 2. Perform this check before `store_payload`, package creation, or any database mutation. If retaining rejected payloads for forensic purposes is necessary, store them in a separate quarantine area that is never processed as trusted tracking data. 3. Make the HTTP receiver authenticate synchronously where practical and return `401 Unauthorized` or `403 Forbidden` for missing or invalid signatures instead of always returning `200 OK`. 4. Define and accept only the documented 17TRACK signature header rather than guessing numerous generic header names, unless compatibility requirements are explicitly documented. 5. For manual file or standard-input ingestion, either: - Require a trusted sidecar containing the original signature header; - Add an explicit signature argument; or - Clearly designate the command as a privileged, trusted local-import mechanism and require an explicit bypass flag. 6. Add tests proving that missing and invalid signatures cannot create packages, update statuses, or insert events when a secret is configured. ]]>

other

Warning
Location
scripts/track17.py:740
Finding
Local parcel labels are implicitly disclosed to 17TRACK<![CDATA[ ## Vulnerability Details **File Location**: `scripts/track17.py:740-767` **Vulnerability Type**: Unnecessary third-party disclosure of user-provided metadata **Risk Level**: Medium ### Vulnerable Code ```python number = _normalise_number(args.number) carrier = int(args.carrier or 0) param = args.param or "" label = args.label tag = args.tag or (label[:32] if label else "") lang = args.lang or (os.environ.get("TRACK17_LANG") or "en") row = upsert_package( conn, number=number, carrier=carrier, param=param, label=label, tag=tag, lang=lang, api_registered=False, ) # Register with API payload_item: Dict[str, Any] = {"number": number} if carrier: payload_item["carrier"] = carrier if tag: payload_item["tag"] = tag if param: payload_item["param"] = param if lang: payload_item["lang"] = lang resp = api_register([payload_item]) ``` ### Technical Analysis The `--label` option is presented as a friendly label for a locally tracked package. However, if the user does not explicitly provide `--tag`, the first 32 characters of the local label are automatically copied into `tag`. That tag is then included in the registration payload sent over HTTPS to the fixed 17TRACK API. Parcel tracking requires the tracking number and, in some cases, carrier or carrier-specific parameters. Automatically transmitting the local descriptive label is not necessary for the core tracking operation and exceeds minimum data disclosure. Labels may contain purchase descriptions, recipient context, names, locations, health-related products, gifts, or other private information. Neither `README.md` nor `SKILL.md` clearly warns that a friendly label is also transmitted to the third-party API as a tag. The transmission destination is the declared 17TRACK service rather than an unknown endpoint, and the token is used as required by that service. The issue is therefore data minimization and transparency, not malicious credential exfiltration ...[truncated 1072 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Keep `--label` strictly local and stop deriving the remote tag from it: ```python label = args.label tag = args.tag or "" ``` 2. Include `tag` in the API request only when the user explicitly supplies `--tag`. 3. Update `README.md`, `SKILL.md`, and command help to identify every field transmitted to 17TRACK, including tracking number, carrier, parameter, language, and an explicitly supplied tag. 4. Warn users that `--param` may contain sensitive carrier-specific information such as a postcode or phone-number suffix and should be supplied only when required. 5. Consider displaying a concise confirmation of fields that will be transmitted before registration, especially in interactive usage. 6. Add a regression test verifying that a package created with `--label` but without `--tag` does not include a `tag` field in the outgoing API payload. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill requires access to environment variables, local file read/write, and network operations, but those capabilities are not explicitly declared as permissions in the skill metadata. This creates a transparency and policy-enforcement gap: reviewers or runtime controls may underestimate what the skill can access, increasing the chance of over-privileged execution or unsafe deployment.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
conn = connect_db(p["db"])
    init_db(conn)

    secret = args.secret or os.environ.get("TRACK17_WEBHOOK_SECRET")

    inbox = p["inbox"]
    files = sorted([f for f in inbox.glob("*.json") if f.is_file()])
Confidence
89% confidence
Finding
The webhook processing path retrieves the shared secret but does not require a valid signature before ingesting and applying webhook data. If the inbox or HTTP listener is reachable by an attacker, forged payloads can create packages and overwrite tracking state, causing integrity issues and potentially misleading automation or users.

Static analysis

No suspicious patterns detected.