T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/gradient_spaces.py:30
- Finding
- Unvalidated S3 Endpoint Can Redirect Documents and Signed Credential Material<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gradient_spaces.py`, lines 30–57 **Vulnerability Type**: Untrusted service endpoint configuration **Risk Level**: Medium ### Vulnerable Code ```python def get_spaces_client( access_key: Optional[str] = None, secret_key: Optional[str] = None, endpoint: Optional[str] = None, ): """Create an S3-compatible client for DO Spaces. Falls back to environment variables if args aren't provided. Args: access_key: Spaces access key. Falls back to DO_SPACES_ACCESS_KEY. secret_key: Spaces secret key. Falls back to DO_SPACES_SECRET_KEY. endpoint: Spaces endpoint URL. Falls back to DO_SPACES_ENDPOINT. Returns: boto3 S3 client configured for DO Spaces. """ access_key = access_key or os.environ.get("DO_SPACES_ACCESS_KEY", "") secret_key = secret_key or os.environ.get("DO_SPACES_SECRET_KEY", "") endpoint = endpoint or os.environ.get( "DO_SPACES_ENDPOINT", "https://nyc3.digitaloceanspaces.com", ) return boto3.client( "s3", endpoint_url=endpoint, aws_access_key_id=access_key, aws_secret_access_key=secret_key, config=Config(signature_version="s3v4"), ) ``` ### Technical Analysis `DO_SPACES_ENDPOINT` is accepted without validating its scheme or hostname. The resulting value is passed directly to `boto3.client` while the client is configured with the user's DigitalOcean Spaces access and secret keys. When an upload, listing, or deletion is performed, boto3 sends an AWS Signature Version 4 authenticated request to the configured endpoint. The secret key itself is not normally transmitted verbatim, but the destination receives the access-key identifier, signed authorization material, request metadata, bucket and object names, and—during upload—the complete document body. Allowing arbitrary S3-compatible endpoints can be legitimate for a general-purpose library. However, thi ...[truncated 1959 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Restrict the endpoint to HTTPS DigitalOcean Spaces hosts: ```python from urllib.parse import urlparse def validate_spaces_endpoint(endpoint: str) -> str: parsed = urlparse(endpoint) hostname = (parsed.hostname or "").lower() if parsed.scheme != "https": raise ValueError("The Spaces endpoint must use HTTPS.") if not ( hostname == "digitaloceanspaces.com" or hostname.endswith(".digitaloceanspaces.com") ): raise ValueError("Only DigitalOcean Spaces endpoints are allowed.") if parsed.username or parsed.password or parsed.query or parsed.fragment: raise ValueError("Invalid Spaces endpoint.") return endpoint ``` 2. Apply validation before creating the boto3 client: ```python endpoint = validate_spaces_endpoint(endpoint) ``` 3. If non-DigitalOcean S3 services must be supported, make that an explicitly documented opt-in mode and require separate credentials rather than reusing DigitalOcean Spaces credentials. 4. Reject plaintext HTTP endpoints and retain TLS certificate verification. 5. Use dedicated, minimally scoped Spaces credentials limited to the required bucket and operations. 6. Update the trust statement to accurately document any supported configurable destinations. ]]>
