Back to skill

Security audit

Proxy Gateway X402

Security checks for vulnerabilities and agentic risk

Overview

This is a real pay-per-use proxy skill, but it combines broad request forwarding with under-scoped wallet-spending behavior that needs careful review before use.

Review before installing or deploying. Do not set USER_EVM_PRIVATE_KEY on any public server, use only a dedicated low-balance wallet for experiments, avoid proxying secrets or internal/private URLs, and self-host only in an isolated environment after adding SSRF protections, payment validation, restrictive CORS, spending limits, and pinned dependencies.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
app/core/security.py:35
Finding

Unrestricted SSRF Through Arbitrary URL Forwarding

Content
View full analysis
bool: """ 验证 URL 格式 - 必须以 http:// 或 https:// 开头 """ if not url: return False return url.startswith(("http://", "https://")) ``` ```python async def fetch_url( self, url: str, method: str = "GET", headers: Optional[Dict[str, str]] = None, body: Optional[str] = None, region: str = "us" ) -> dict: proxy_url = f"http://localhost:{self.upstream_mixed_port}" transport = httpx.AsyncHTTPTransport(proxy=proxy_url) async with httpx.AsyncClient( timeout=30.0, follow_redirects=True, transport=transport ) as client: request_headers = headers or {} request_headers.setdefault("User-Agent", "ProxyGateway/0.3.0") response = await client.request( method=method.upper(), url=url, headers=request_headers, content=body ) return { 'success': True, 'status_code': response.status_code, 'headers': dict(response.headers), 'content': response.text, 'content_type': response.headers.get('content-type') } ``` ### Technical Analysis URL validation verifies only that the input begins with `http://` or `https://`. It does not parse the destination or reject: - Loopback addresses such as `127.0.0.1` and `::1` - RFC 1918 private networks - Link-local and cloud metadata addresses - Localhost or internal DNS names - Alternative or encoded IP representations - Hostnames that resolve to private addresses - DNS rebinding - Redirects from public hosts to restricted destinations The forwarding implementation also enables `follow_redirects=T ...[truncated 1478 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
app/middleware/x402_payment.py:139
Finding

Payment Verification Accepts Unrelated or Zero-Value Token Transactions

Content
View full analysis
bool: """Validate that the transaction matches our requirements""" # Check recipient if receipt.get("to", "").lower() != self.usdc_contract.address.lower(): return False # Additional validation could check: # - Transfer amount # - Recipient address in event logs # - Token contract return True ``` ### Technical Analysis The verifier checks only that: 1. A transaction receipt exists. 2. Its status indicates success. 3. The transaction's `to` field is the configured USDC contract. It does not decode the transaction input or event logs to verify that the developer wallet received USDC. It also does not validate the transferred amount, sender, request identity, confirmation depth, or a unique payment challenge. Consequently, a successful call to the token contract may be accepted even when it transfers tokens to a di ...[truncated 1200 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
app/middleware/x402_payment.py:134
Finding

Payment Proof Cache Enables Unlimited Replay During the Cache Window

Content
View full analysis
bool: """Check if payment is in cache and not expired""" if tx_hash in self._verified_payments: cached_time = self._verified_payments[tx_hash] if datetime.now() - cached_time < self._payment_cache_ttl: return True # Expired, remove from cache del self._verified_payments[tx_hash] return False def _cache_payment(self, tx_hash: str): """Cache verified payment""" self._verified_payments[tx_hash] = datetime.now() # Cleanup old entries cutoff = datetime.now() - self._payment_cache_ttl expired = [ tx for tx, ts in self._verified_payments.items() if ts < cutoff ] for tx in expired: del self._verified_payments[tx] ``` The security manifest incorrectly describes this behavior as replay prevention: ```yaml mitigations: - User private key never leaves client environment - All payments verified on-chain before service delivery - Payment proofs cached to prevent replay attacks ``` ### Technical Analysis A previously verified transaction is automatically accepted whenever it remains in the five-minute cache. Therefore, caching explicitly authorizes replay instead of preventing it. There is no consumed-payment marker, payment nonce, request binding, or atomic uniqueness check. The cache is also process-local, so separate workers, application restarts, or multiple server instances cannot consistently identify previously used proofs. ### Attack Path 1. The attacker obtains one t ...[truncated 860 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
app/routers/proxy.py:168
Finding

Unauthenticated Auto-Pay Endpoint Exposes Server Wallet Spending Authority

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unbounded and Unhashed Dependency Resolution Creates Supply-Chain Exposure

Content
View full analysis
=0.100.0 uvicorn[standard]>=0.23.0 httpx>=0.24.0 pydantic>=2.0.0 pydantic-settings>=2.0.0 python-dotenv>=1.0.0 # x402 / Web3 web3>=6.0.0 eth-account>=0.8.0 # Caching cachetools>=5.3.0 # Logging structlog>=23.0.0 # Testing pytest>=7.4.0 pytest-asyncio>=0.21.0 httpretty>=1.1.0 ``` ### Technical Analysis Every dependency uses an unbounded minimum-version constraint. The project has no lockfile, upper bounds, or package hashes. A new installation can therefore receive dependency versions that were never reviewed or tested with this code. No evidence of typosquatted package names, malicious package sources, or nonstandard package indexes was identified. The risk arises from unrestricted future resolution and missing artifact integrity controls. This is particularly relevant because the dependency set includes blockchain signing, transaction construction, HTTP forwarding, and server framework components. ### Attack Path 1. A future package version is compromised, malicious, or behaviorally incompatible. 2. An operator performs a fresh `pip install -r requirements.txt`. 3. The resolver selects the latest version satisfying each `>=` constraint. 4. The unreviewed package executes during installation or application runtime. 5. In the worst case, compromised dependency code gains access to wallet keys, transaction data, forwarded request content, or server privileges. ### Impact Assessment Potential impact includes: - Non-reproducible deployments - Silent installation of unreviewed releases - Runtime incompatibility or security regressions - Compromise of wallet-signing operations - Exposure of proxy request data and environment secrets - Increased difficulty validating exactly what code is deployed The finding represents preventable ...[truncated 91 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (83)

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 · README.md (reported line 23)May include surrounding context.

md
- Response content

**DO NOT use this proxy for:**
- API keys or access tokens
- Private keys or passwords
- Personal or sensitive data
- Internal/private network endpoints

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 · SECURITY.md (reported line 28)May include surrounding context.

md
- Response content

**DO NOT use this proxy for:**
- API keys or access tokens
- Private keys or passwords
- Personal or sensitive data
- Internal/private network endpoints

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 134)May include surrounding context.

md
pip install -r requirements.txt

# 4. Configure environment
cp .env.example .env
# Edit .env with your settings:
# - HOSTED_WALLET: Your Polygon wallet address
# - ADMIN_TOKEN: Secure random string (16+ chars)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 135)May include surrounding context.

2. Configure Environment

bash
cp .env.example .env
# Edit .env with your settings:
# - DEVELOPER_WALLET: Your wallet to receive payments
# - PRICE_PER_REQUEST: Set your price (default: 0.001)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 269)May include surrounding context.

2. Configure Environment

bash
cp .env.example .env
# Edit .env with your settings:
# - DEVELOPER_WALLET: Your wallet to receive payments
# - PRICE_PER_REQUEST: Set your price (default: 0.001)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

2. Configure Environment

bash
cp .env.example .env
# Edit .env with your settings:
# - DEVELOPER_WALLET: Your wallet to receive payments
# - PRICE_PER_REQUEST: Set your price (default: 0.001)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

2. Configure Environment

bash
cp .env.example .env
# Edit .env with your settings:
# - DEVELOPER_WALLET: Your wallet to receive payments
# - PRICE_PER_REQUEST: Set your price (default: 0.001)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · app/core/config.py (reported line 63)May include surrounding context.

python
DATABASE_URL: Optional[str] = Field(default=None, description="PostgreSQL database URL")
    
    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"
        case_sensitive = True

Missing User Warnings

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

Telling users to set a private-key environment variable for auto-pay normalizes storing highly sensitive credentials in a way that may be exposed through logs, process inspection, crash reports, container metadata, or downstream tooling. Because the same key can authorize fund transfers, compromise of that variable can directly lead to asset theft, making this materially risky in a payment-enabled agent context.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The payment verification logic does not verify the actual ERC-20 transfer semantics promised by the middleware flow. It only checks that the transaction succeeded and that the transaction target was the USDC contract, so any successful call to that contract could be treated as payment, even if no required amount was transferred to the developer wallet. In this context, that can let clients bypass paywall enforcement and obtain paid service without paying.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code signs and broadcasts a token transfer using a user-supplied private key, but there is no confirmation, consent checkpoint, spending cap enforcement, or prominent warning in this component. In an agent/skill setting, this is especially dangerous because higher-level automation may invoke it automatically, causing real fund movement with minimal user awareness.

Content

No source excerpt is available for this finding.

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The example explicitly posts JSON request data to an external proxy API, which means request metadata and payloads leave the local trust boundary. Even though the README includes privacy warnings, the documented usage still encourages a data-flow pattern that is dangerous for agent deployments handling sensitive context.

Content

Scanner excerpt · README.md (reported line 77)May include surrounding context.

python
import requests

response = requests.post(
    "https://proxy.easky.cn/api/v1/fetch",
    headers={"X-Client-ID": "my_agent_001"},
    json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The example explicitly posts JSON request data to an external proxy API, which means request metadata and payloads leave the local trust boundary. Even though the README includes privacy warnings, the documented usage still encourages a data-flow pattern that is dangerous for agent deployments handling sensitive context.

Content

Scanner excerpt · README.md (reported line 77)May include surrounding context.

python
import requests

response = requests.post(
    "https://proxy.easky.cn/api/v1/fetch",
    headers={"X-Client-ID": "my_agent_001"},
    json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The sample code combines external transmission with an authentication header, which normalizes sending operational credentials to a third-party proxy. If reused in agent environments, this could enable abuse of the proxy account and disclosure of proxied content or metadata.

Content

Scanner excerpt · README.md (reported line 95)May include surrounding context.

python
# Use your user_id as API Key after deposit
response = requests.post(
    "https://proxy.easky.cn/api/v1/fetch",
    headers={"X-API-Key": "my_agent_001"},
    json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The sample code combines external transmission with an authentication header, which normalizes sending operational credentials to a third-party proxy. If reused in agent environments, this could enable abuse of the proxy account and disclosure of proxied content or metadata.

Content

Scanner excerpt · README.md (reported line 95)May include surrounding context.

python
# Use your user_id as API Key after deposit
response = requests.post(
    "https://proxy.easky.cn/api/v1/fetch",
    headers={"X-API-Key": "my_agent_001"},
    json={

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 · README.md (reported line 99)May include surrounding context.

md
"https://proxy.easky.cn/api/v1/fetch",
    headers={"X-API-Key": "my_agent_001"},
    json={
        "url": "https://api.example.com/data",
        "method": "GET"
    }
)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
96% confidence
Finding

Documenting CORS_ORIGINS=* as an example/default encourages overly permissive cross-origin access, which can expose the proxy API to unintended browser-based use from any website. In a service that accepts credentials and proxies arbitrary requests, permissive CORS increases the chance of misuse, token leakage through browser contexts, and abuse from untrusted origins.

Content

Scanner excerpt · README.md (reported line 285)May include surrounding context.

FREE_TRIAL_LIMIT=10 COST_PER_REQUEST=0.001

CORS

CORS_ORIGINS=*

text

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This duplicate finding identifies the same external transmission behavior: a request to a third-party proxy endpoint that can observe forwarded request contents. In this context, the risk is amplified by the skill’s purpose of brokering arbitrary outbound requests for an agent, which may unintentionally include sensitive data.

Content

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

md
import json

# Method 1: Auto-pay (if USER_EVM_PRIVATE_KEY is set)
response = requests.post(
    "https://proxy-gateway-x402.easky.cn/api/v1/fetch",
    json={
        "url": "https://api.github.com/users/github",

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This duplicate finding identifies the same external transmission behavior: a request to a third-party proxy endpoint that can observe forwarded request contents. In this context, the risk is amplified by the skill’s purpose of brokering arbitrary outbound requests for an agent, which may unintentionally include sensitive data.

Content

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

md
import json

# Method 1: Auto-pay (if USER_EVM_PRIVATE_KEY is set)
response = requests.post(
    "https://proxy-gateway-x402.easky.cn/api/v1/fetch",
    json={
        "url": "https://api.github.com/users/github",

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This duplicate finding reflects the same underlying issue in the manual payment path: outbound request data is sent to a third-party proxy without a strong nearby warning about confidentiality risks. Users may assume they are merely paying for bandwidth rather than delegating full request visibility.

Content

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

md
# Method 2: Manual payment
# First call returns 402 Payment Required
response = requests.post(
    "https://proxy-gateway-x402.easky.cn/api/v1/fetch",
    json={"url": "https://example.com/api", "method": "GET"}
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This duplicate finding reflects the same underlying issue in the manual payment path: outbound request data is sent to a third-party proxy without a strong nearby warning about confidentiality risks. Users may assume they are merely paying for bandwidth rather than delegating full request visibility.

Content

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

md
# Method 2: Manual payment
# First call returns 402 Payment Required
response = requests.post(
    "https://proxy-gateway-x402.easky.cn/api/v1/fetch",
    json={"url": "https://example.com/api", "method": "GET"}
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

This example again sends data to the external proxy and includes payment proof material in headers, increasing the amount of transaction-related metadata disclosed to the service. While the tx hash is not a secret by itself, combining payment and request metadata at a third-party relay raises privacy and correlation risks.

Content

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

md
# Pay 0.001 USDC to the specified address
# Then retry with payment proof
response = requests.post(
    "https://proxy-gateway-x402.easky.cn/api/v1/fetch",
    headers={"X-Payment-Response": json.dumps({"tx_hash": "0x..."})},
    json={"url": "https://example.com/api", "method": "GET"}

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.