Back to skill

Security audit

CCS Receipt Batch Audit — Ed25519 Verification

Security checks for vulnerabilities and agentic risk

Overview

This skill can verify receipts locally, but it also includes an under-scoped online path that can send receipts and credentials to configurable endpoints despite prominent offline claims.

Install only if you are comfortable with an optional networked audit mode. Use local mode only for sensitive receipts, avoid setting CCS_API_TOKEN or payment-proof environment variables in the same shell unless you intend to use the hosted service, and do not use --endpoint unless you fully trust that destination. Treat verification results with care because the JCS number handling may reject some standards-compliant receipts containing floating-point values.

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/ccs_online_client.py:57
Finding
Authentication credentials and receipt data can be transmitted to arbitrary or plaintext endpoints<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ccs_online_client.py`, lines 57-59 and 91-105 **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code ```python def resolve_endpoint(cli_value: str | None = None) -> str: ep = cli_value or os.environ.get("CCS_API_ENDPOINT") or DEFAULT_ENDPOINT return ep.rstrip("/") ``` ```python def call(path: str, body: dict, endpoint: str | None = None, timeout: float = 30.0) -> dict: """POST JSON to the CCS API; return the parsed JSON response. Raises PaymentRequiredError on HTTP 402 (bill printed to stderr), CCSAPIError on other non-2xx. The request body is never logged. """ ep = resolve_endpoint(endpoint) data = json.dumps(body, ensure_ascii=False).encode("utf-8") if len(data) > MAX_BODY_BYTES: raise CCSAPIError(413, {"error": f"请求体超过 {MAX_BODY_BYTES} 字节上限"}) headers = {"Content-Type": "application/json; charset=utf-8", "User-Agent": "CCS-CLI/1.0 (channel=clawhub)"} api_key = os.environ.get("CCS_API_TOKEN") if api_key: headers["X-API-Key"] = api_key # A2M: payment proof from the Alipay checkout flow (official contract # header name is Payment-Proof). CCS_PAY_TOKEN kept as a legacy alias. proof = os.environ.get("CCS_PAYMENT_PROOF") or os.environ.get("CCS_PAY_TOKEN") if proof: headers["Payment-Proof"] = proof req = urllib.request.Request(ep + path, data=data, headers=headers, method="POST") ``` The online mode is invoked from `scripts/batch_audit.py`, lines 145-149: ```python if args.online: import ccs_online_client as client # noqa: E402 try: rep = client.call("/v1/audit/batch", body, endpoint=args.endpoint, timeout=90) ``` ### Technical Analysis The online client accepts an endpoint from the `--endpoint` option or the `CCS_API_ENDPOINT` environment variable without vali ...[truncated 2060 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse endpoints using `urllib.parse.urlsplit` and reject malformed URLs. 2. Require the `https` scheme for all online requests. If plaintext transport is required for local testing, place it behind a clearly named opt-in option such as `--allow-insecure-http`. 3. Reject URL user information, fragments, unexpected ports, loopback hosts, private networks, link-local ranges, and cloud metadata addresses unless a separately authorized development mode explicitly permits them. 4. Bind credentials to trusted origins. Do not automatically send production API tokens or payment proofs to arbitrary custom endpoints. 5. Require credentials to be supplied for a specific endpoint or maintain an explicit allowlist of origins authorized to receive each credential. 6. Disable redirects or validate every redirect target and strip sensitive headers when the origin changes. 7. Display the final destination and request explicit confirmation before sending receipt contents to a non-default endpoint. 8. Update `SKILL.md` to explain custom-endpoint trust requirements and accurately state that HTTPS is enforced only after the code implements that enforcement. 9. Add automated tests verifying rejection of HTTP, malformed URLs, loopback/private/metadata destinations, and cross-origin credential forwarding. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/core_ccs.py:211
Finding
Non-compliant RFC 8785 floating-point canonicalization can produce incorrect cryptographic verification results<![CDATA[ ## Vulnerability Details **File Location**: `scripts/core_ccs.py`, lines 211-226 **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: Medium ### Vulnerable Code ```python # Use repr — Python's repr already gives the shortest round-trip # decimal, matching ECMAScript's "Number To String" algorithm for # all finite doubles. Normalize the exponent to lowercase 'e'. s = repr(x) if "e" in s: s = s.replace("e+", "e").replace("e-0", "e-") # Python repr may produce e-0<digit>; keep the digit # e.g. 1e-07 -> need to preserve -> "1e-7". The replace above # turns "e-0" into "e-", leaving "7". Good. # But Python sometimes uses e+0X too; handled by e+ -> e. # Python repr for floats in [1e-4, 1e21) uses no exponent, matching # ECMAScript thresholds (1e-6 / 1e21 for toString base-10). Note: # the threshold difference does not affect canonical equivalence for # our receipt domain (timestamps, integer counts) and we document that # we follow Python's shortest round-trip; for full ES compliance on # values 1e-6..1e-4 the outputs are numerically identical and cross- # implementer canonical forms differ only in presentation — JCS # canonicalization is self-consistent within this implementation which # is what verification requires (same implementation on sign & verify). return s ``` ### Technical Analysis RFC 8785 requires JSON numbers to be serialized according to ECMAScript number-serialization rules. The implementation instead uses Python's `repr(float)` and performs limited exponent normalization. The source acknowledges that Python and ECMAScript use different notation thresholds for some values, including values in the approximate range from `1e-6` to `1e-4`. Although two representations may be numerically equivalent, cryptographic canonicalization requires by ...[truncated 1648 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the `repr(float)` logic with an exact implementation of the RFC 8785 and ECMAScript number-serialization algorithm. 2. Prefer a mature, independently reviewed JCS implementation when dependency policy permits it. 3. Add the official RFC 8785 test vectors, including numeric boundary and exponent-format cases. 4. Add cross-language interoperability tests against compliant JavaScript and other JCS implementations. 5. Test values around `1e-6`, `1e-4`, `1e21`, negative zero, exponent normalization boundaries, and shortest-round-trip edge cases. 6. Remove the claim of full RFC 8785 compliance until all official and cross-implementation test vectors pass. 7. If the supported receipt schema intends to prohibit floating-point fields, enforce that restriction during schema validation and document it explicitly rather than relying on expected input patterns. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tainted flow: 'req' from os.environ.get (line 104, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = urllib.request.Request(ep + path, data=data, headers=headers,
                                 method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            return json.loads(r.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        try:
Confidence
98% confidence
Finding
The request sent to urllib includes headers populated from environment variables, specifically X-API-Key and Payment-Proof, so sensitive credentials flow directly to a network destination. Because the endpoint is user-configurable via CLI or environment and the skill claims to be fully offline, this creates a real exfiltration risk if the module is invoked in an untrusted or misconfigured context.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The manifest presents the skill as requiring no declared permissions while the documented behavior includes access to environment variables, shell execution via Python invocation, and optional network communication. This weakens operator trust boundaries because users may run the skill assuming it is strictly offline and minimally privileged, while the skill can access sensitive context such as environment-provided tokens and send data externally in online mode.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill is described as a fully offline, zero-network batch verifier, but the documented behavior includes an online mode that uploads receipt batches and public keys to a remote endpoint and allows endpoint override. That mismatch is security-relevant because users may provide sensitive audit artifacts under a false assumption of local-only processing; endpoint override further increases the risk of exfiltration to attacker-controlled services.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest advertises fully offline and zero-network operation, yet the skill documentation itself states that receipts and issuer public keys are transmitted over HTTPS when --online is used. Even if opt-in, the contradiction materially increases the chance of unsafe use because the privacy boundary is misstated in the primary metadata users rely on when selecting the skill.

Context-Inappropriate Capability

Medium
Confidence
78% confidence
Finding
An optional hosted submission path is not inherently malicious, but in a skill whose stated purpose is offline receipt verification it introduces an unnecessary data egress channel for potentially sensitive audit evidence. Because receipts may contain operational logs or decision metadata, this additional capability expands the attack surface and can be abused or misconfigured to leak data, especially when combined with configurable endpoints.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The skill metadata promises fully offline, zero-network batch verification, but the script explicitly documents an --online mode that sends receipts and the issuer public key over HTTPS. This mismatch is security-relevant because operators may rely on the manifest/privacy claims and unknowingly expose sensitive audit receipts to a remote service.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The CLI help text advertises optional online verification despite the skill being described as offline-only. In a security-sensitive auditing tool, this discrepancy can mislead users into invoking a mode that transmits receipt contents externally, violating expectations about isolation and data handling.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
When --online is used, the script transmits the full batch body, including receipts and public key material, to a remote endpoint that may be user-specified via --endpoint. Even though the key is public, the receipts themselves may contain sensitive audit evidence, and allowing arbitrary endpoints increases the risk of intentional or accidental data exfiltration.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
This file implements an HTTP client with outbound requests, configurable endpoints, and remote response handling, directly contradicting the declared 'fully offline' and 'zero network calls' scope of the skill. That mismatch is security-relevant because users and orchestrators may grant the skill trust, data, or execution rights on the assumption that no network egress occurs.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code supports payment-gated API access, billing flows, and payment proof submission, which are unrelated to offline Ed25519/JCS receipt batch auditing. Such hidden capability expansion increases attack surface, introduces secret handling, and may enable unexpected charges or remote data disclosure under a misleading skill description.

Intent-Code Divergence

Medium
Confidence
84% confidence
Finding
The module docstring states it is shared by 'pay-skill' CLI wrappers, which is inconsistent with the declared purpose of an offline batch-audit skill. While not an exploit by itself, this strongly suggests code reuse across mismatched trust boundaries and increases the likelihood that operators will unknowingly execute network/payment code in a supposedly offline tool.

Description-Behavior Mismatch

Critical
Confidence
99% confidence
Finding
The file's functionality is materially inconsistent with the advertised skill purpose. Instead of offline Ed25519/JCS receipt verification, it implements MCP configuration security scanning, which indicates a capability/purpose mismatch that can mislead operators, break security assumptions, and cause the wrong code to be trusted or executed in sensitive workflows.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The MCP server capability triage logic is unrelated to batch receipt verification and expands the effective behavior surface of the skill in an unjustified way. In a security-sensitive verification skill, hidden or extraneous analysis logic is dangerous because it can be used to smuggle alternate functionality, confuse reviewers, and undermine assurance that the tool is strictly offline and single-purpose.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
The skill is advertised as an offline CCS receipt batch verifier, but the code also exposes a separate MCP/Agent configuration auditing capability. This hidden scope expansion increases the attack surface and can cause callers, reviewers, or policy engines to grant trust and permissions based on an incomplete manifest, enabling unintended use of a security-scanning feature outside the declared purpose.

Context-Inappropriate Capability

High
Confidence
93% confidence
Finding
Including MCP/Agent security scanning logic in a receipt-verification skill is an unjustified capability addition that violates least functionality. Even though this path is static and makes no network calls, it allows the skill to process unrelated configuration objects and produce security judgments, which may be abused for policy bypass, unexpected data handling, or trust confusion in systems that only approved a verifier.

Intent-Code Divergence

Medium
Confidence
86% confidence
Finding
The module docstring documents only receipt-verification behavior while omitting the later MCP security-checkup function. Security-sensitive hidden functionality undermines reviewer understanding, automated governance, and user consent, making it easier for extra capabilities to evade scrutiny even if the code itself is not directly exploitative.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
raise CCSAPIError(413, {"error": f"请求体超过 {MAX_BODY_BYTES} 字节上限"})
    headers = {"Content-Type": "application/json; charset=utf-8",
               "User-Agent": "CCS-CLI/1.0 (channel=clawhub)"}
    api_key = os.environ.get("CCS_API_TOKEN")
    if api_key:
        headers["X-API-Key"] = api_key
    # A2M: payment proof from the Alipay checkout flow (official contract
Confidence
93% confidence
Finding
Reading CCS_API_TOKEN from the environment is not inherently unsafe, but in this file the value is forwarded as an HTTP header to a remotely configurable endpoint. In the context of a skill advertised as offline, this constitutes secret harvesting/exfiltration risk because users would not reasonably expect the skill to collect and transmit API credentials.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
headers["X-API-Key"] = api_key
    # A2M: payment proof from the Alipay checkout flow (official contract
    # header name is Payment-Proof). CCS_PAY_TOKEN kept as a legacy alias.
    proof = os.environ.get("CCS_PAYMENT_PROOF") or os.environ.get("CCS_PAY_TOKEN")
    if proof:
        headers["Payment-Proof"] = proof
    req = urllib.request.Request(ep + path, data=data, headers=headers,
Confidence
96% confidence
Finding
The code reads CCS_PAYMENT_PROOF or CCS_PAY_TOKEN from environment variables and transmits the value as a Payment-Proof header. Payment proofs are sensitive artifacts; forwarding them to a configurable remote endpoint from a supposedly offline audit skill creates credential/token leakage risk and could enable billing abuse or replay depending on server-side controls.

Static analysis

No suspicious patterns detected.