Back to skill

Security audit

champro-api

Security checks for vulnerabilities and agentic risk

Overview

The CHAMPRO ordering skill is mostly transparent about its purpose, but ordinary inputs can redirect authenticated API calls and choose local download overwrite paths, which could expose credentials or damage files.

Review before installing. Use only trusted CHAMPRO credentials, do not allow untrusted prompts or generated JSON to supply api_base, cb_base, output_path, skip_validation, confirm, or production, and prefer running production orders only after a sandbox rehearsal. Avoid storing this skill where untrusted users can invoke its CLI with arbitrary JSON.

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/client.py:94
Finding

Caller-Controlled API Base URLs Can Exfiltrate Credentials and Customer Data

Content
View full analysis
None: self._api_key = api_customer_key self._cb_key = cb_customer_key self.api_base = (api_base or os.environ.get("CHAMPRO_API_BASE") or API_BASE).rstrip("/") self.cb_base = (cb_base or os.environ.get("CHAMPRO_CB_BASE") or CB_BASE).rstrip("/") self.timeout = int(os.environ.get("CHAMPRO_TIMEOUT") or timeout) self._session = None ``` The CLI forwards all input properties directly to action handlers: ```python args = read_stdin_json() try: result = handler(**args) ``` Credentials are subsequently sent to the selected base URL. For example: ```python def product_info(self, product_master: str) -> dict[str, Any]: payload = self._request( "GET", f"{self.api_base}/api/Order/ProductInfo", params={"ProductMaster": product_master, "APICustomerKey": self.api_key}, ) return self._checked(payload, "ProductInfo") ``` Order requests also send the API key and full order body to the selected endpoint: ```python path = _PLACE_ORDER_PROD if production else _PLACE_ORDER_SANDBOX body = {**body, "APICustomerKey": self.api_key} payload = self._request("POST", f"{self.api_base}{path}", json_body=body) ``` ### Technical Analysis The Skill documents `api_base` and `cb_base` as mock-testing overrides, but these values are accepted from ordinary action JSON through unrestricted `**credentials` parameters. `ChamproClient` ...[truncated 2758 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/custom_builder.py:265
Finding

Custom Builder Download Allows Arbitrary File Overwrite

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description presents a comprehensive operational toolkit covering many CHAMPRO workflows and API-backed actions. The supplied code chunk is much narrower: it defines an offline shipping-method lookup wrapper and an error-code explainer based on local tables/imports. While these functions could be supportive pieces of the larger toolkit, the actual behavior in this chunk does not match the declared primary purpose and capabilities. There are no undeclared risky behaviors, but there is a strong description-versus-code scope mismatch.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/champro.py (reported line 15)May include surrounding context.

python
Actions:

  Setup
    check-access        Credentials + egress IP readiness. Orders nothing.
                        {}

  Catalog  (fills PromoStandards PPC's MOQ / lead-time gap)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/api_reference.md (reported line 34)May include surrounding context.

md
| CB `GetOrderInfo` | `[]` — no error channel whatsoever |

`ProductInfo` returning `MOQ: 0, MOQCustom: 0` on an auth failure is the
nastiest of these: those are legal values, so a client reading them without
checking `Error` concludes the product has no minimum.

Real HTTP errors do occur, and mean something different: CB `GetFile` 404s on

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation explicitly states that ProofFileURL must be a public asset that CHAMPRO fetches server-side, but it does not warn users that any supplied URL and referenced file will be transmitted to and retrieved by a third party. This can lead to unintended disclosure of sensitive proof documents, signed URLs, embedded query secrets, or internal-only asset locations if callers pass non-public or sensitive links.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The example listener processes event.data from any origin and forwards the Design Session ID to application code before verifying where the message came from. In an iframe/embed context, any page or nested frame can send a crafted postMessage, which can cause the parent app to accept attacker-controlled session identifiers or trigger unintended workflow steps tied to ordering, proof retrieval, or roster handling.

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 · references/promostandards_gaps.md (reported line 20)May include surrounding context.

md
| MED (Media Content) | 1.1.0 | Production | none |
| PRODUCT (Product Data) | 1.0.0 and 2.0.0 | Production | none |

All five live under `https://api.dc-onesource.com/xml/CHAMPRO/<SERVICE>/<VERSION>/soap`.

Re-check with:

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/promostandards_gaps.md (reported line 127)May include surrounding context.

bash
K=00000000-0000-0000-0000-000000000000
curl -sS "https://api.champrosports.com/api/Order/ProductInfo?ProductMaster=JSBJ8&APICustomerKey=$K"
curl -sS -X POST https://api.champrosports.com/api/Order/Inventory \
  -H 'Content-Type: application/json' \
  -d "{\"APICustomerKey\":\"$K\",\"Orders\":[{\"OrderItems\":[{\"SKU\":\"BBS44ABS\"}]}]}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/promostandards_gaps.md (reported line 127)May include surrounding context.

md
return {
        "request_body": report["envelope"],
        "note": "APICustomerKey is injected at send time and is deliberately absent here.",
        "sandbox_url": "https://api.champrosports.com/api/OrderSandBox/PlaceOrder",
        "production_url": "https://api.champrosports.com/api/Order/PlaceOrder",
        "validation": report,
    }

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/promostandards_gaps.md (reported line 128)May include surrounding context.

md
return {
        "request_body": report["envelope"],
        "note": "APICustomerKey is injected at send time and is deliberately absent here.",
        "sandbox_url": "https://api.champrosports.com/api/OrderSandBox/PlaceOrder",
        "production_url": "https://api.champrosports.com/api/Order/PlaceOrder",
        "validation": report,
    }

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/orders.py (reported line 178)May include surrounding context.

python
return {
        "request_body": report["envelope"],
        "note": "APICustomerKey is injected at send time and is deliberately absent here.",
        "sandbox_url": "https://api.champrosports.com/api/OrderSandBox/PlaceOrder",
        "production_url": "https://api.champrosports.com/api/Order/PlaceOrder",
        "validation": report,
    }

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/orders.py (reported line 179)May include surrounding context.

python
return {
        "request_body": report["envelope"],
        "note": "APICustomerKey is injected at send time and is deliberately absent here.",
        "sandbox_url": "https://api.champrosports.com/api/OrderSandBox/PlaceOrder",
        "production_url": "https://api.champrosports.com/api/Order/PlaceOrder",
        "validation": report,
    }

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/orders.py (reported line 275)May include surrounding context.

python
production: bool = False,
    autowarehouse: bool = False,
    product_masters: list[str] | None = None,
    skip_validation: bool = False,
    **credentials: Any,
) -> dict[str, Any]:
    """Submit one or more orders. **External write.**

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

This logic allows a caller to bypass blocking local validation and still submit external write operations by setting skip_validation=true. In an ordering skill that can place real production orders, bypassing pre-flight checks increases the risk of malformed, unintended, or policy-violating orders being sent, especially because the API is non-idempotent and has no cancel path.

Content

Scanner excerpt · scripts/orders.py (reported line 304)May include surrounding context.

python
product_masters=product_masters,
        **credentials,
    )
    if not report["valid"] and not skip_validation:
        return {
            "outcome": "not_sent",
            "reason": "validation_failed",

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

The user-facing message explicitly instructs callers to pass skip_validation:true to send anyway, normalizing bypass of safety controls. In this skill context, that is more dangerous because the function performs real external order placement and the comments note there is no cancel endpoint and ambiguous failures must not be retried.

Content

Scanner excerpt · scripts/orders.py (reported line 310)May include surrounding context.

python
"reason": "validation_failed",
            "message": (
                f"{report['blocking_count']} blocking finding(s). Fix them, or pass "
                "skip_validation:true to send anyway."
            ),
            "validation": report,
        }

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/validation.py (reported line 81)May include surrounding context.

python
# -- ship-to (code 24) ---------------------------------------------------
    for attr, wire_name in _REQUIRED_SHIPTO:
        if not str(getattr(order, attr, "") or "").strip():
            findings.append(_finding("error", "24", f"{wire_name} is required."))
    if not str(order.phone or "").strip():
        findings.append(_finding("error", "24", "Phone is required."))

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/validation.py (reported line 249)May include surrounding context.

python
)
            )
        for attr, name in (("lead_time", "LeadTime"), ("proof_file_url", "ProofFileURL")):
            if str(getattr(order, attr) or "").strip():
                findings.append(
                    _finding("error", "07", f"{name} is a CUSTOM field on a STOCK order.")
                )

Static analysis

No suspicious patterns detected.