T09 · Insecure Skill Coding Practices
- Location
postiz_api_integration.py:6- Finding
Configurable Postiz Endpoint Can Disclose API Credentials and Uploaded Content
- Content
View full analysis
Vulnerability Details
File Location:
postiz_api_integration.py, lines 6-51
Vulnerability Type: Unvalidated credential-bearing network destination
Risk Level: HighVulnerable Code
python POSTIZ_API_KEY = os.getenv("POSTIZ_API_KEY") POSTIZ_API_URL = os.getenv("POSTIZ_API_URL", "https://api.postiz.com/v1") def _auth_headers() -> Dict[str, str]: if not POSTIZ_API_KEY: raise PostizError("POSTIZ_API_KEY is not set in environment") return {"Authorization": f"Bearer {POSTIZ_API_KEY}"} def upload_media_to_postiz(file_path: str) -> Dict[str, Any]: """Uploads a local image file to Postiz and returns the parsed JSON response. Returns a dict with at least an `id` or `url` depending on API. """ p = Path(file_path) if not p.exists(): raise PostizError(f"file not found: {file_path}") url = f"{POSTIZ_API_URL}/media/upload" headers = _auth_headers() with p.open('rb') as fh: files = {'file': fh} resp = requests.post(url, headers=headers, files=files) try: resp.raise_for_status() except Exception as e: raise PostizError(f"upload failed: {e} - {resp.text}") return resp.json() def create_tiktok_draft(media_ids: List[str], caption: str, privacy_level: str = "SELF_ONLY") -> Dict[str, Any]: url = f"{POSTIZ_API_URL}/tiktok/create_draft" headers = _auth_headers() headers.update({"Content-Type": "application/json"}) payload = { "type": "carousel", "media_ids": media_ids, "caption": caption, "privacy_level": privacy_level, } resp = requests.post(url, headers=headers, json=payload)Technical Analysis
POSTIZ_API_URLis accepted directly from the process environment without validating its scheme or destination host. The same destination receives anAuthorization: Bearerheader containing the Postiz API key, sel ...[truncated 1447 chars]- Remediation
View remediation
Remediation Suggestions
- Parse
POSTIZ_API_URLwithurllib.parse.urlparse. - Require the
httpsscheme and reject embedded credentials, fragments, and malformed hostnames. - Allowlist the official Postiz API hostname by default.
- If self-hosted Postiz installations must be supported, require explicit opt-in and display or log the resolved destination before transmitting credentials.
- Use separate, least-privileged API credentials for self-hosted or development endpoints.
- Add connection and read timeouts to every request.
- Consider loading configuration at invocation time rather than module import time so validated configuration is consistently applied.
- Avoid including untrusted response bodies in errors where those messages could later be exposed to logs or users.
- Parse
